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
impl Sampler
Sourcepub fn parser(&self) -> &UnsafeParser
pub fn parser(&self) -> &UnsafeParser
Record parser of the sampler.
Sourcepub fn aux_tracer(&self, exp: u8) -> Result<AuxTracer<'_>>
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.
pub fn pause(&self) -> Result<()>
pub fn resume(&self) -> Result<()>
Sourcepub fn enable_counter_with(&self, max_samples: u32) -> Result<()>
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);
Sourcepub fn sample_on(&self, freq_or_count: u64) -> Result<()>
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.
Sourcepub fn counter_time_enabled(&self) -> u64
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.
Sourcepub fn counter_time_running(&self) -> u64
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.