use crate::core::BPF;
use crate::error::BccError;
use crate::perf_event::Event;
use bcc_sys::bccapi::bpf_prog_type_BPF_PROG_TYPE_PERF_EVENT as BPF_PROG_TYPE_PERF_EVENT;
#[derive(Default)]
pub struct PerfEvent {
handler: Option<String>,
event: Option<Event>,
sample_period: Option<u64>,
sample_frequency: Option<u64>,
pid: Option<i32>,
cpu: Option<usize>,
group_fd: Option<i32>,
}
impl PerfEvent {
pub fn new() -> Self {
Default::default()
}
pub fn handler(mut self, name: &str) -> Self {
self.handler = Some(name.to_owned());
self
}
pub fn event(mut self, event: Event) -> Self {
self.event = Some(event);
self
}
pub fn sample_period(mut self, count: Option<u64>) -> Self {
self.sample_period = count;
self
}
pub fn sample_frequency(mut self, hz: Option<u64>) -> Self {
self.sample_frequency = hz;
self
}
pub fn pid(mut self, pid: Option<i32>) -> Self {
self.pid = pid;
self
}
pub fn cpu(mut self, cpu: Option<usize>) -> Self {
self.cpu = cpu;
self
}
pub fn group_fd(mut self, group_fd: Option<i32>) -> Self {
self.group_fd = group_fd;
self
}
pub fn attach(self, bpf: &mut BPF) -> Result<(), BccError> {
if self.event.is_none() {
return Err(BccError::InvalidPerfEvent {
message: "event is required".to_string(),
});
}
if self.handler.is_none() {
return Err(BccError::InvalidPerfEvent {
message: "handler is required".to_string(),
});
}
if (self.sample_period.unwrap_or(0) == 0) as i32
^ (self.sample_frequency.unwrap_or(0) == 0) as i32
== 0
{
return Err(BccError::InvalidPerfEvent {
message: "exactly one of sample period or sample frequency is required".to_string(),
});
}
let handler = self.handler.unwrap();
let event = self.event.unwrap();
let code_fd = bpf.load(&handler, BPF_PROG_TYPE_PERF_EVENT, 0, 0)?;
let ev_type = event.ev_type();
let ev_config = event.ev_config();
let perf_event = crate::core::PerfEvent::new(
code_fd,
ev_type,
ev_config,
self.sample_period.unwrap_or(0),
self.sample_frequency.unwrap_or(0),
self.pid.unwrap_or(-1),
self.cpu,
self.group_fd.unwrap_or(-1),
)
.map_err(|_| BccError::AttachPerfEvent { event })?;
bpf.perf_events.insert(perf_event);
Ok(())
}
}