blob: d79b749335f06bb5793352c60962c646a9190ae0 [file] [log] [blame] [edit]
//! Events we can monitor or count.
//!
//! There are three general categories of event:
//!
//! - [`Hardware`] events are counted by the processor itself. This
//! includes things like clock cycles, instructions retired, and cache and
//! branch prediction statistics.
//!
//! - [`Cache`] events, also counted by the processor, offer a more
//! detailed view of the processor's cache counters. You can
//! select which level of the cache hierarchy to observe,
//! discriminate between data and instruction caches, and so on.
//!
//! - [`Software`] events are counted by the kernel. This includes things
//! like context switches, page faults, and so on.
//!
//! The `Event` type is just an enum with a variant for each of the above types,
//! which all implement `Into<Event>`.
//!
//! Linux supports many more kinds of events than this module covers, including
//! events specific to particular make and model of processor, and events that
//! are dynamically registered by drivers and kernel modules. If something you
//! want is missing, think about the best API to expose it, and submit a pull
//! request!
//!
//! [`Hardware`]: enum.Hardware.html
//! [`Software`]: enum.Software.html
//! [`Cache`]: struct.Cache.html
#![allow(non_camel_case_types)]
use perf_event_open_sys::bindings;
/// Any sort of event. This is a sum of the [`Hardware`],
/// [`Software`], and [`Cache`] types, which all implement
/// `Into<Event>`.
///
/// [`Hardware`]: enum.Hardware.html
/// [`Software`]: enum.Software.html
/// [`Cache`]: struct.Cache.html
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Event {
#[allow(missing_docs)]
Hardware(Hardware),
#[allow(missing_docs)]
Software(Software),
#[allow(missing_docs)]
Cache(Cache),
}
impl Event {
pub(crate) fn r#type(&self) -> bindings::perf_type_id {
match self {
Event::Hardware(_) => bindings::PERF_TYPE_HARDWARE,
Event::Software(_) => bindings::PERF_TYPE_SOFTWARE,
Event::Cache(_) => bindings::PERF_TYPE_HW_CACHE,
}
}
pub(crate) fn config(self) -> u64 {
match self {
Event::Hardware(hw) => hw as _,
Event::Software(sw) => sw as _,
Event::Cache(cache) => cache.as_config(),
}
}
}
/// Hardware counters.
///
/// These are counters implemented by the processor itself. Such counters vary
/// from one architecture to the next, and even different models within a
/// particular architecture will often change the way they expose this data.
/// This is a selection of portable names for values that can be obtained on a
/// wide variety of systems.
///
/// Each variant of this enum corresponds to a particular `PERF_COUNT_HW_`...
/// value supported by the [`perf_event_open`][man] system call.
///
/// [man]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html
#[repr(u32)]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Hardware {
/// Total cycles. Be wary of what happens during CPU frequency scaling.
CPU_CYCLES = bindings::PERF_COUNT_HW_CPU_CYCLES,
/// Retired instructions. Be careful, these can be affected by various
/// issues, most notably hardware interrupt counts.
INSTRUCTIONS = bindings::PERF_COUNT_HW_INSTRUCTIONS,
/// Cache accesses. Usually this indicates Last Level Cache accesses but
/// this may vary depending on your CPU. This may include prefetches and
/// coherency messages; again this depends on the design of your CPU.
CACHE_REFERENCES = bindings::PERF_COUNT_HW_CACHE_REFERENCES,
/// Cache misses. Usually this indicates Last Level Cache misses; this is
/// intended to be used in conjunction with the
/// PERF_COUNT_HW_CACHE_REFERENCES event to calculate cache miss rates.
CACHE_MISSES = bindings::PERF_COUNT_HW_CACHE_MISSES,
/// Retired branch instructions. Prior to Linux 2.6.35, this used the wrong
/// event on AMD processors.
BRANCH_INSTRUCTIONS = bindings::PERF_COUNT_HW_BRANCH_INSTRUCTIONS,
/// Mispredicted branch instructions.
BRANCH_MISSES = bindings::PERF_COUNT_HW_BRANCH_MISSES,
/// Bus cycles, which can be different from total cycles.
BUS_CYCLES = bindings::PERF_COUNT_HW_BUS_CYCLES,
/// Stalled cycles during issue. (since Linux 3.0)
STALLED_CYCLES_FRONTEND = bindings::PERF_COUNT_HW_STALLED_CYCLES_FRONTEND,
/// Stalled cycles during retirement. (since Linux 3.0)
STALLED_CYCLES_BACKEND = bindings::PERF_COUNT_HW_STALLED_CYCLES_BACKEND,
/// Total cycles; not affected by CPU frequency scaling. (since Linux 3.3)
REF_CPU_CYCLES = bindings::PERF_COUNT_HW_REF_CPU_CYCLES,
}
impl From<Hardware> for Event {
fn from(hw: Hardware) -> Event {
Event::Hardware(hw)
}
}
/// Software counters, implemented by the kernel.
///
/// Each variant of this enum corresponds to a particular `PERF_COUNT_SW_`...
/// value supported by the [`perf_event_open`][man] system call.
///
/// [man]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html
#[repr(u32)]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Software {
/// This reports the CPU clock, a high-resolution per-CPU timer.
CPU_CLOCK = bindings::PERF_COUNT_SW_CPU_CLOCK,
/// This reports a clock count specific to the task that is running.
TASK_CLOCK = bindings::PERF_COUNT_SW_TASK_CLOCK,
/// This reports the number of page faults.
PAGE_FAULTS = bindings::PERF_COUNT_SW_PAGE_FAULTS,
/// This counts context switches. Until Linux 2.6.34, these were all
/// reported as user-space events, after that they are reported as happening
/// in the kernel.
CONTEXT_SWITCHES = bindings::PERF_COUNT_SW_CONTEXT_SWITCHES,
/// This reports the number of times the process has migrated to a new CPU.
CPU_MIGRATIONS = bindings::PERF_COUNT_SW_CPU_MIGRATIONS,
/// This counts the number of minor page faults. These did not require disk
/// I/O to handle.
PAGE_FAULTS_MIN = bindings::PERF_COUNT_SW_PAGE_FAULTS_MIN,
/// This counts the number of major page faults. These required disk I/O to
/// handle.
PAGE_FAULTS_MAJ = bindings::PERF_COUNT_SW_PAGE_FAULTS_MAJ,
/// (since Linux 2.6.33) This counts the number of alignment faults. These
/// happen when unaligned memory accesses happen; the kernel can handle
/// these but it reduces performance. This happens only on some
/// architectures (never on x86).
ALIGNMENT_FAULTS = bindings::PERF_COUNT_SW_ALIGNMENT_FAULTS,
/// (since Linux 2.6.33) This counts the number of emulation faults. The
/// kernel sometimes traps on unimplemented instructions and emulates them
/// for user space. This can negatively impact performance.
EMULATION_FAULTS = bindings::PERF_COUNT_SW_EMULATION_FAULTS,
/// (since Linux 3.12) This is a placeholder event that counts nothing.
/// Informational sample record types such as mmap or comm must be
/// associated with an active event. This dummy event allows gathering such
/// records without requiring a counting event.
DUMMY = bindings::PERF_COUNT_SW_DUMMY,
}
impl From<Software> for Event {
fn from(hw: Software) -> Event {
Event::Software(hw)
}
}
/// A cache event.
///
/// A cache event has three identifying characteristics:
///
/// - which cache to observe ([`which`])
///
/// - what sort of request it's handling ([`operation`])
///
/// - whether we want to count all cache accesses, or just misses
/// ([`result`]).
///
/// For example, to measure the L1 data cache's miss rate:
///
/// # use perf_event::{Builder, Group};
/// # use perf_event::events::{Cache, CacheOp, CacheResult, Hardware, WhichCache};
/// # fn main() -> std::io::Result<()> {
/// // A `Cache` value representing L1 data cache read accesses.
/// const ACCESS: Cache = Cache {
/// which: WhichCache::L1D,
/// operation: CacheOp::READ,
/// result: CacheResult::ACCESS,
/// };
///
/// // A `Cache` value representing L1 data cache read misses.
/// const MISS: Cache = Cache { result: CacheResult::MISS, ..ACCESS };
///
/// // Construct a `Group` containing the two new counters, from which we
/// // can get counts over matching periods of time.
/// let mut group = Group::new()?;
/// let access_counter = Builder::new().group(&mut group).kind(ACCESS).build()?;
/// let miss_counter = Builder::new().group(&mut group).kind(MISS).build()?;
/// # Ok(()) }
///
/// [`which`]: enum.WhichCache.html
/// [`operation`]: enum.CacheOp.html
/// [`result`]: enum.CacheResult.html
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Cache {
/// Which cache is being monitored? (data, instruction, ...)
pub which: WhichCache,
/// What operation is being monitored? (read, write, etc.)
pub operation: CacheOp,
/// All accesses, or just misses?
pub result: CacheResult,
}
impl From<Cache> for Event {
fn from(hw: Cache) -> Event {
Event::Cache(hw)
}
}
impl Cache {
fn as_config(&self) -> u64 {
self.which as u64 | ((self.operation as u64) << 8) | ((self.result as u64) << 16)
}
}
/// A cache whose events we would like to count.
///
/// This is used in the `Cache` type as part of the identification of a cache
/// event. Each variant here corresponds to a particular
/// `PERF_COUNT_HW_CACHE_...` constant supported by the [`perf_event_open`][man]
/// system call.
///
/// [man]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html
#[repr(u32)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum WhichCache {
/// for measuring Level 1 Data Cache
L1D = bindings::PERF_COUNT_HW_CACHE_L1D,
/// for measuring Level 1 Instruction Cache
L1I = bindings::PERF_COUNT_HW_CACHE_L1I,
/// for measuring Last-Level Cache
LL = bindings::PERF_COUNT_HW_CACHE_LL,
/// for measuring the Data TLB
DTLB = bindings::PERF_COUNT_HW_CACHE_DTLB,
/// for measuring the Instruction TLB
ITLB = bindings::PERF_COUNT_HW_CACHE_ITLB,
/// for measuring the branch prediction unit
BPU = bindings::PERF_COUNT_HW_CACHE_BPU,
/// (since Linux 3.1) for measuring local memory accesses
NODE = bindings::PERF_COUNT_HW_CACHE_NODE,
}
/// What sort of cache operation we would like to observe.
///
/// This is used in the `Cache` type as part of the identification of a cache
/// event. Each variant here corresponds to a particular
/// `PERF_COUNT_HW_CACHE_OP_...` constant supported by the
/// [`perf_event_open`][man] system call.
///
/// [man]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html
#[repr(u32)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum CacheOp {
/// Read accesses.
READ = bindings::PERF_COUNT_HW_CACHE_OP_READ,
/// Write accesses.
WRITE = bindings::PERF_COUNT_HW_CACHE_OP_WRITE,
/// Prefetch accesses.
PREFETCH = bindings::PERF_COUNT_HW_CACHE_OP_PREFETCH,
}
#[repr(u32)]
/// What sort of cache result we're interested in observing.
///
/// `ACCESS` counts the total number of operations performed on the cache,
/// whereas `MISS` counts only those requests that the cache could not satisfy.
/// Treating `MISS` as a fraction of `ACCESS` gives you the cache's miss rate.
///
/// This is used used in the `Cache` type as part of the identification of a
/// cache event. Each variant here corresponds to a particular
/// `PERF_COUNT_HW_CACHE_RESULT_...` constant supported by the
/// [`perf_event_open`][man] system call.
///
/// [man]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum CacheResult {
/// to measure accesses
ACCESS = bindings::PERF_COUNT_HW_CACHE_RESULT_ACCESS,
/// to measure misses
MISS = bindings::PERF_COUNT_HW_CACHE_RESULT_MISS,
}