use std::os::raw::c_int;
use errno::errno;
use libc::*;
use crate::Error;
use crate::ffi::perf_event_attr;
IOCTL!(PERF_EVENT_IOC_ENABLE, b'$', 0);
IOCTL!(PERF_EVENT_IOC_DISABLE, b'$', 1);
IOCTL!(PERF_EVENT_IOC_RESET, b'$', 3);
IOCTL!(PERF_EVENT_IOC_SET_BPF, b'$', 8, c_int);
pub fn perf_event_open(attr: *const perf_event_attr, pid: pid_t, cpu: c_int, group_fd: c_int, flags: u64) -> Result<c_int, Error> {
unsafe {
match syscall(SYS_perf_event_open, attr, pid, cpu, group_fd, flags) {
-1 => Err(errno())?,
rc => Ok(rc as c_int),
}
}
}
pub fn perf_event_ioc_enable(fd: c_int) -> Result<(), Error> {
unsafe {
match ioctl(fd, PERF_EVENT_IOC_ENABLE) {
0 => Ok(()),
_ => Err(errno())?
}
}
}
pub fn perf_event_ioc_disable(fd: c_int) -> Result<(), Error> {
unsafe {
match ioctl(fd, PERF_EVENT_IOC_DISABLE) {
0 => Ok(()),
_ => Err(errno())?
}
}
}
pub fn perf_event_ioc_reset(fd: c_int) -> Result<(), Error> {
unsafe {
match ioctl(fd, PERF_EVENT_IOC_RESET) {
0 => Ok(()),
_ => Err(errno())?
}
}
}
pub fn perf_event_ioc_set_bpf(fd: c_int, pfd: c_int) -> Result<(), Error> {
unsafe {
match ioctl(fd, PERF_EVENT_IOC_SET_BPF, pfd) {
0 => Ok(()),
_ => Err(errno())?
}
}
}
#[cfg(test)]
mod tests {
use std::error::Error;
use std::fs::File;
use std::io::Read;
use std::mem;
use crate::ffi::*;
use super::*;
#[test]
fn test_perf_events() {
check_paranoia(2).unwrap();
let mut attr = perf_event_attr::default();
attr.type_ = PERF_TYPE_SOFTWARE;
attr._bitfield_1 = 1 | 1 << 5 | 1 << 6;
attr.config = PERF_COUNT_SW_TASK_CLOCK;
let fd = perf_event_open(&attr, 0, -1, -1, 0).unwrap();
perf_event_ioc_reset(fd).unwrap();
perf_event_ioc_enable(fd).unwrap();
println!("hello, world!");
perf_event_ioc_disable(fd).unwrap();
let mut count: c_ulong = 0;
unsafe {
let data = &mut count as *mut _ as *mut c_void;
let size = mem::size_of_val(&count);
read(fd, data, size);
}
assert!(count > 0);
}
fn check_paranoia(level: u8) -> Result<(), Box<dyn Error>> {
let mut file = File::open("/proc/sys/kernel/perf_event_paranoid")?;
let mut line = String::new();
file.read_to_string(&mut line)?;
if line.trim().parse::<u8>()? > level {
panic!(r"
test requires paranoia level <= {0} or CAP_SYS_ADMIN
echo {0} > /proc/sys/kernel/perf_event_paranoid
", level);
}
Ok(())
}
}