Struct Sampler

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

A sampled perf event.

A sampler for a sampler perf event consists of two things: a Counter, and a memory-mapped ring buffer into which the kernel periodically writes events. The specific event is configured on construction and can vary from changes to the memory mapping associated with a process, to sampling call stacks, to getting the output from a bpf program running in the kernel, and more.

This sampler type provides direct access to the bytes written by the kernel without doing any parsing of the emitted records. To actually read the involved fields you will need to parse them yourself. See the perf_event_open man page for documentation on how the sample records are represented in memory.

Implementations§

Source§

impl Sampler

Source

pub fn into_counter(self) -> Counter

Convert this sampler back into a counter.

This will close the ringbuffer associated with the sampler.

Source

pub fn as_counter(&self) -> &Counter

Access the underlying counter for this sampler.

Source

pub fn as_counter_mut(&mut self) -> &mut Counter

Mutably access the underlying counter for this sampler.

Source

pub fn next_record(&mut self) -> Option<Record<'_>>

Read the next record from the ring buffer.

This method does not block. If you want blocking behaviour, use next_blocking instead.

It is possible to get readiness notifications for when events are present in the ring buffer (e.g. for async code). See the documentation on the perf_event_open manpage for details on how to do this.

Source

pub fn next_blocking(&mut self, timeout: Option<Duration>) -> Option<Record<'_>>

Read the next record from the ring buffer. This method will block (with an optional timeout) until a new record is available.

If this sampler is only enabled for a single process and that process exits, this method will return None even if no timeout is passed. Note that this only works on Linux 3.18 and above.

§Panics

This method will panic if an unexpected error is returned from libc::poll. There are only two cases where this can happen:

  • the current process has run out of file descriptors, or,
  • the kernel couldn’t allocate memory for internal poll datastructures.
Source

pub fn read_user(&self) -> UserReadData

Read the value of this counter directly from userspace.

Some CPU architectures allow performance counters to be read directly from userspace without having to go through the kernel. This can be much faster than a normal counter read but the tradeoff is that can only be done under certain conditions.

This method allows you to read the counter value, time_enabled, and time_running without going through the kernel, if allowed by the combination of architecture, kernel, and counter. time_enabled and time_running are always read but will be less accurate on architectures that do not provide a timestamp counter readable from userspace.

§Restrictions

In order for counter values to be read using this method the following must be true:

  • the CPU architecture must support reading counters from userspace,
  • the counter must be recording for the current process,
  • perf-event2 must have support for the relevant CPU architecture, and,
  • the counter must correspond to a hardware counter.

Note that, despite the above being true, the kernel may still not support userspace reads for other reasons. Hardware events should usually be supported but anything beyond that is unlikely. See the supported architectures table below to see which are supported by perf-event2.

Accurate timestamps also require that the kernel, CPU, and perf-event2 support them. They have similar restrictions to counter reads and will just return the base values set by the kernel otherwise. These will may be somewhat accurate but are likely to be out-of-date.

§Supported Architectures
ArchitectureCounter ReadTimestamp Read
x86/x86_64yesyes

If you would like to add support for a new architecture here please submit a PR!

Methods from Deref<Target = 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 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 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 Sampler

Source§

fn as_raw_fd(&self) -> RawFd

Extracts the raw file descriptor. Read more
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 Deref for Sampler

Source§

type Target = Counter

The resulting type after dereferencing.
Source§

fn deref(&self) -> &Self::Target

Dereferences the value.
Source§

impl DerefMut for Sampler

Source§

fn deref_mut(&mut self) -> &mut Self::Target

Mutably dereferences the value.
Source§

impl IntoRawFd for Sampler

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<P, T> Receiver for P
where P: Deref<Target = T> + ?Sized, T: ?Sized,

Source§

type Target = T

🔬This is a nightly-only experimental API. (arbitrary_self_types)
The target type on which the method may be called.
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,