in src/samplers/scheduler/mod.rs [146:208]
fn initialize_bpf_perf(&mut self) -> Result<(), std::io::Error> {
let cpus = crate::common::hardware_threads().unwrap();
let interval = self.interval() as u64;
let frequency = if interval > 1000 {
1
} else if interval == 0 {
1
} else {
1000 / interval
};
let code = format!(
"{}\n{}",
format!("#define NUM_CPU {}", cpus),
include_str!("perf.c").to_string()
);
let mut perf_array_attached = false;
if let Ok(mut bpf) = bcc::BPF::new(&code) {
for statistic in &self.statistics {
if let Some(table) = statistic.perf_table() {
if let Some(event) = statistic.event() {
perf_array_attached = true;
if PerfEventArray::new()
.table(&format!("{}_array", table))
.event(event)
.attach(&mut bpf)
.is_err()
{
if !self.common().config().general().fault_tolerant() {
fatal!("failed to initialize perf bpf for event: {:?}", event);
} else {
error!("failed to initialize perf bpf for event: {:?}", event);
}
}
}
}
}
debug!("attaching software event to drive perf counter sampling");
if perf_array_attached {
if PerfEvent::new()
.handler("do_count")
.event(Event::Software(SoftwareEvent::CpuClock))
.sample_frequency(Some(frequency))
.attach(&mut bpf)
.is_err()
{
if !self.common().config().general().fault_tolerant() {
fatal!("failed to initialize perf bpf for cpu");
} else {
error!("failed to initialize perf bpf for cpu");
}
}
}
self.perf = Some(Arc::new(Mutex::new(BPF { inner: bpf })));
} else if !self.common().config().general().fault_tolerant() {
fatal!("failed to initialize perf bpf");
} else {
error!("failed to initialize perf bpf. skipping scheduler perf telemetry");
}
Ok(())
}