Struct Sampler

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

Event sampler.

This type provides the event sampling function of perf_event_open, which can capture the context when the event happens, helpling us to gain in-depth understanding of the system status at that time, similar to the perf record command.

§Examples

use std::thread;
use std::time::Duration;

use perf_event_open::config::{Cpu, Opts, Proc, Size};
use perf_event_open::count::Counter;
use perf_event_open::event::hw::Hardware;

// Count retired instructions on any process, CPU 0.
let event = Hardware::Instr;
let target = (Proc::ALL, Cpu(0));

let mut opts = Opts::default();
opts.sample_format.user_stack = Some(Size(32)); // Dump 32-bytes user stack.

let counter = Counter::new(event, target, opts).unwrap();
let sampler = counter.sampler(10).unwrap(); // Allocate 2^10 pages to store samples.

counter.enable().unwrap();
thread::sleep(Duration::from_millis(10));
counter.disable().unwrap();

for it in sampler.iter() {
    println!("{:-?}", it);
}

Implementations§

Source§

impl Sampler

Source

pub fn iter(&self) -> Iter<'_>

Returns a record iterator over the kernel ring-buffer.

Source

pub fn parser(&self) -> &UnsafeParser

Record parser of the sampler.

Source

pub fn aux_tracer(&self, exp: u8) -> Result<AuxTracer<'_>>

Create an AUX tracer for this sampler.

The AUX tracer needs a ring-buffer to store data, and 1 + 2^exp pages will be allocated for this.

Multiple calls to this method just duplicates the existing AUX tracer, AUX tracers from the same sampler shares the same ring-buffer in the kernel space, so exp should be the same.

Source

pub fn pause(&self) -> Result<()>

Source

pub fn resume(&self) -> Result<()>

Source

pub fn enable_counter_with(&self, max_samples: u32) -> Result<()>

Enables the counter until the maximum number of samples has been generated.

The counter will be disabled if max_samples is reached.

§Examples
use std::{thread, time::Duration};

use perf_event_open::config::{Cpu, Opts, Proc, SampleOn};
use perf_event_open::count::Counter;
use perf_event_open::event::sw::Software;

let event = Software::TaskClock;
let target = (Proc::ALL, Cpu(0));
let mut opts = Opts::default();
opts.sample_on = SampleOn::Count(1_000_000); // 1ms

let counter = Counter::new(event, target, opts).unwrap();
let sampler = counter.sampler(5).unwrap();

sampler.enable_counter_with(10).unwrap();
thread::sleep(Duration::from_millis(20));

assert_eq!(sampler.iter().count(), 10);

Furthermore, we can capture the overflow events by enabling I/O signaling from the perf event fd.

On each overflow, POLL_IN is indicated if max_samples has not been reached. Otherwise, POLL_HUP is indicated.

 use perf_event_open::config::{Cpu, Opts, Proc, SampleOn};
 use perf_event_open::count::Counter;
 use perf_event_open::event::sw::Software;
 use std::mem::MaybeUninit;
 use std::os::fd::AsRawFd;
 use std::ptr::null_mut;
 use std::sync::atomic::AtomicBool;
 use std::sync::atomic::Ordering as MemOrd;

 const MAX_SAMPLES: usize = 3;

 let event = Software::TaskClock;
 let target = (Proc::CURRENT, Cpu::ALL);
 let mut opts = Opts::default();
 opts.sample_on = SampleOn::Count(1_000_000); // 1ms

 let counter = Counter::new(event, target, opts).unwrap();

 // Enable I/O signals from perf event fd to the current process.
 let fd = counter.file().as_raw_fd();
 unsafe {
     libc::fcntl(fd, libc::F_SETFL, libc::O_ASYNC);
     // The value of `F_SETSIG` is 10, and libc crate does not have
     // that binding (same as `POLL_IN` and `POLL_HUP` below).
     libc::fcntl(fd, 10, libc::SIGIO);
     libc::fcntl(fd, libc::F_SETOWN, libc::getpid());
 }

 static IN: AtomicBool = AtomicBool::new(false);
 static HUP: AtomicBool = AtomicBool::new(false);

 fn handler(num: i32, info: *const libc::siginfo_t) {
     assert_eq!(num, libc::SIGIO);
     match unsafe { *info }.si_code {
         1 => IN.store(true, MemOrd::Relaxed),  // POLL_IN
         6 => HUP.store(true, MemOrd::Relaxed), // POLL_HUP
         _ => unreachable!(),
     }
 }

 let act = libc::sigaction {
     sa_sigaction: handler as _,
     sa_mask: unsafe { MaybeUninit::zeroed().assume_init() },
     sa_flags: libc::SA_SIGINFO,
     sa_restorer: None,
 };
 unsafe { libc::sigaction(libc::SIGIO, &act as _, null_mut()) };

 let sampler = counter.sampler(5).unwrap();
 sampler.enable_counter_with(MAX_SAMPLES as _).unwrap();

 let iter = &mut sampler.iter();
 let mut count = 0;
 while !HUP.load(MemOrd::Relaxed) {
     while IN.swap(false, MemOrd::Relaxed) {
         count += iter.count();
     }
 }
 count += iter.count();
 assert_eq!(count, MAX_SAMPLES);
Source

pub fn sample_on(&self, freq_or_count: u64) -> Result<()>

Reset overflow condition.

How to interpret freq_or_count depends on how the counter was created. This means that the new frequency will be applied if the counter was created with SampleOn::Freq, and so will the count.

Source

pub fn counter_time_enabled(&self) -> u64

Counter’s enabled time.

Same as time returned by Counter::stat, but much cheaper since the value is read from memory instead of system call.

Source

pub fn counter_time_running(&self) -> u64

Counter’s running time.

Same as time returned by Counter::stat, but much cheaper since the value is read from memory instead of system call.

Trait Implementations§

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.