Struct Counter

Source
pub struct Counter { /* private fields */ }
Expand description

A counter for a single kernel or hardware event.

A counter represents a single performance monitoring counter. When building the counter you select the event you would like it to count. Once the counter is created, then you can enable or disable it, call its read method to retrieve its current value, and reset it to zero.

§Groups

The kernel allows for counters to be grouped together. A group of counters will be scheduled onto the CPU as a unit. This allows you to directly compare the values collected by multiple counters.

There are two ways to go about working with groups:

A counter represents a single performance monitoring counter. While creating the counter - via Builder - you select the event you would like to count. Once the counter is created, then you can enable or disable it, call its read method to retrieve the current count (or counts if it is a Group), and reset it to zero.

Implementations§

Source§

impl Counter

Source

pub fn id(&self) -> u64

Return this counter’s kernel-assigned unique id.

Source

pub fn config(&self) -> &ParseConfig<Native>

The ParseConfig for this Counter.

Source

pub fn enable(&mut self) -> Result<()>

Allow this Counter to begin counting its designated event.

This does not affect whatever value the Counter had previously; new events add to the current count. To clear a Counter, use reset.

Note that, depending on how it was configured, a counter may start off enabled or be automatically enabled by the kernel when an event occurs. For example, setting enable_on_exec will cause this counter to be automatically enabled when the current process calls execve(2).

If you want to enable all counters in the same group as this one then use enable_group instead.

§Examples

Enable an individual counter:

use perf_event::events::Hardware;
use perf_event::Builder;

let mut counter = Builder::new(Hardware::INSTRUCTIONS).build()?;
counter.enable()?;
// ...
assert_ne!(counter.read()?, 0);
Source

pub fn enable_group(&mut self) -> Result<()>

Enable all counters in the same group as this one.

This does not affect whatever value the Counter had previously; new events add to the current count. To clear a counter group, use reset_group.

See enable for the version that only applies to the current counter.

§Examples

Enable all counters in a group:

use perf_event::events::Hardware;
use perf_event::{Builder, Group};

let mut group = Group::new()?;
let mut cycles = Builder::new(Hardware::CPU_CYCLES).build_with_group(&mut group)?;
group.enable()?;
// ...
assert_ne!(cycles.read()?, 0);
Source

pub fn disable(&mut self) -> Result<()>

Make this Counter stop counting its designated event.

This does not affect the value of this Counter.

To disable all counters in the group use disable_group.

§Examples

Disable a single counter:

use perf_event::events::Hardware;
use perf_event::Builder;

let mut counter = Builder::new(Hardware::INSTRUCTIONS).build()?;
counter.enable()?;

// Counter is continuously updating
let val1 = counter.read()?;
let val2 = counter.read()?;
counter.disable()?;

// Counter is no longer updating
let val3 = counter.read()?;
let val4 = counter.read()?;

assert_ne!(val1, val2);
assert_eq!(val3, val4);
Source

pub fn disable_group(&mut self) -> Result<()>

Disable all counters in the same group as this one.

This does not affect the counter values.

To disable only this counter use disable.

Source

pub fn reset(&mut self) -> Result<()>

Reset the value of this Counter to zero.

To reset the value of all counters in the current group use reset_group.

§Examples

Reset a single counter

use perf_event::events::Hardware;
use perf_event::Builder;

let mut counter = Builder::new(Hardware::INSTRUCTIONS).build()?;
counter.enable()?;
// ...
counter.disable()?;

assert_ne!(counter.read()?, 0);
counter.reset()?;
assert_eq!(counter.read()?, 0);
Source

pub fn reset_group(&mut self) -> Result<()>

Reset the value of all counters in the same group as this one to zero.

To only reset the value of this counter use reset.

Source

pub fn set_bpf(&mut self, bpf: RawFd) -> Result<()>

Attach an eBPF program to this counter.

This will only work if this counter was created as a kprobe tracepoint event.

This method corresponds to the IOC_SET_BPF ioctl.

Source

pub fn sampled(self, map_len: usize) -> Result<Sampler>

Map a buffer for samples from this counter, returning a Sampler that can be used to access them.

There are some restrictions on the size of the mapped buffer. To accomodate this map_len will always be rounded up to the next power-of-two multiple of the system page size. There will always be at least two pages allocated for the ring buffer: one for the control data structures, and one for actual data.

§Example

This example shows creating a sample to record mmap events within the current process. If you do this early enough, you can then track what libraries your process is loading.

use perf_event::events::Software;
use perf_event::Builder;

let mut sampler = Builder::new(Software::DUMMY)
    .mmap(true)
    .build()?
    .sampled(128)?;
Source§

impl Counter

Source

pub fn read(&mut self) -> Result<u64>

Return this Counter’s current value as a u64.

Consider using read_full or (if read_format has the required flags) read_count_and_time instead. There are limitations around how many hardware counters can be on a single CPU at a time. If more counters are requested than the hardware can support then the kernel will timeshare them on the hardware. Looking at just the counter value gives you no indication that this has happened.

If you would like to read the values for an entire group then you will need to use read_group (and set ReadFormat::GROUP) instead.

§Errors

This function may return errors in the following notable cases:

  • ENOSPC is returned if the read_format that this Counter was built with does not match the format of the data. This can also occur if read_format contained options not supported by this crate.
  • If the counter is part of a group and was unable to be pinned to the CPU then reading will return an error with kind UnexpectedEof.

Other errors are also possible under unexpected conditions (e.g. EBADF if the file descriptor is closed).

§Example
use perf_event::events::Hardware;
use perf_event::Builder;

let mut counter = Builder::new(Hardware::INSTRUCTIONS).enabled(true).build()?;

let instrs = counter.read()?;
Source

pub fn read_full(&mut self) -> Result<CounterData>

Return all data that this Counter is configured to provide.

The exact fields that are returned within the CounterData struct depend on what was specified for read_format when constructing this counter. This method is the only one that gives access to all values returned by the kernel.

If this Counter was created with ReadFormat::GROUP then this will read the entire group but only return the data for this specific counter.

§Errors

This function may return errors in the following notable cases:

  • ENOSPC is returned if the read_format that this Counter was built with does not match the format of the data. This can also occur if read_format contained options not supported by this crate.
  • If the counter is part of a group and was unable to be pinned to the CPU then reading will return an error with kind UnexpectedEof.

Other errors are also possible under unexpected conditions (e.g. EBADF if the file descriptor is closed).

§Example
use std::time::Duration;

use perf_event::events::Hardware;
use perf_event::{Builder, ReadFormat};

let mut counter = Builder::new(Hardware::INSTRUCTIONS)
    .read_format(ReadFormat::TOTAL_TIME_RUNNING)
    .enabled(true)
    .build()?;
// ...
let data = counter.read_full()?;
let instructions = data.count();
let time_running = data.time_running().unwrap();
let ips = instructions as f64 / time_running.as_secs_f64();

println!("instructions/s: {ips}");
Source

pub fn read_group(&mut self) -> Result<GroupData>

Read the values of all the counters in the current group.

Note that unless ReadFormat::GROUP was specified when building this Counter this will only read the data for the current Counter.

§Errors

This function may return errors in the following notable cases:

  • ENOSPC is returned if the read_format that this Counter was built with does not match the format of the data. This can also occur if read_format contained options not supported by this crate.
  • If the counter is part of a group and was unable to be pinned to the CPU then reading will return an error with kind UnexpectedEof.

Other errors are also possible under unexpected conditions (e.g. EBADF if the file descriptor is closed).

§Example

Compute the CPI for a region of code:

use perf_event::events::Hardware;
use perf_event::{Builder, ReadFormat};

let mut instrs = Builder::new(Hardware::INSTRUCTIONS)
    .read_format(ReadFormat::GROUP)
    .build()?;
let mut cycles = Builder::new(Hardware::CPU_CYCLES).build_with_group(&mut instrs)?;

instrs.enable_group()?;
// ...
instrs.disable_group()?;

let data = instrs.read_group()?;
let instrs = data[&instrs];
let cycles = data[&cycles];

println!("CPI: {}", cycles as f64 / instrs as f64);
Source

pub fn read_count_and_time(&mut self) -> Result<CountAndTime>

Return this Counter’s current value and timesharing data.

Some counters are implemented in hardware, and the processor can run only a fixed number of them at a time. If more counters are requested than the hardware can support, the kernel timeshares them on the hardware.

This method returns a CountAndTime struct, whose count field holds the counter’s value, and whose time_enabled and time_running fields indicate how long you had enabled the counter, and how long the counter was actually scheduled on the processor. This lets you detect whether the counter was timeshared, and adjust your use accordingly. Times are reported in nanoseconds.

§Errors

See the man page for possible errors when reading from the counter. This method will also return an error if read_format does not include both TOTAL_TIME_ENABLED and TOTAL_TIME_RUNNING.

§Example
let cat = counter.read_count_and_time()?;
if cat.time_running == 0 {
    println!("No data collected.");
} else if cat.time_running < cat.time_enabled {
    // Note: this way of scaling is accurate, but `u128` division
    // is usually implemented in software, which may be slow.
    println!(
        "{} instructions (estimated)",
        (cat.count as u128 * cat.time_enabled as u128 / cat.time_running as u128) as u64
    );
} else {
    println!("{} instructions", cat.count);
}

Note that Group also has a read method, which reads all its member Counters’ values at once.

Trait Implementations§

Source§

impl AsMut<Counter> for &mut Counter

Source§

fn as_mut(&mut self) -> &mut Counter

Converts this type into a mutable reference of the (usually inferred) input type.
Source§

impl AsMut<Counter> for &mut Group

Source§

fn as_mut(&mut self) -> &mut Counter

Converts this type into a mutable reference of the (usually inferred) input type.
Source§

impl AsMut<Counter> for Sampler

Source§

fn as_mut(&mut self) -> &mut Counter

Converts this type into a mutable reference of the (usually inferred) input type.
Source§

impl AsRawFd for Counter

Source§

fn as_raw_fd(&self) -> RawFd

Extracts the raw file descriptor. Read more
Source§

impl AsRef<Counter> for &Counter

Source§

fn as_ref(&self) -> &Counter

Converts this type into a shared reference of the (usually inferred) input type.
Source§

impl AsRef<Counter> for &Group

Source§

fn as_ref(&self) -> &Counter

Converts this type into a shared reference of the (usually inferred) input type.
Source§

impl AsRef<Counter> for Sampler

Source§

fn as_ref(&self) -> &Counter

Converts this type into a shared reference of the (usually inferred) input type.
Source§

impl Debug for Counter

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Index<&Counter> for GroupData

Source§

type Output = u64

The returned type after indexing.
Source§

fn index(&self, ctr: &Counter) -> &u64

Performs the indexing (container[index]) operation. Read more
Source§

impl IntoRawFd for Counter

Source§

fn into_raw_fd(self) -> RawFd

Consumes this object, returning the raw underlying file descriptor. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> EventData for T
where T: Send + Sync,