mirror of https://github.com/aya-rs/aya
Add support for PerfEvent programs.
parent
269be03a89
commit
c39dff6025
@ -0,0 +1,115 @@
|
||||
use crate::{generated::bpf_prog_type::BPF_PROG_TYPE_PERF_EVENT, sys::perf_event_open};
|
||||
|
||||
pub use crate::generated::perf_type_id;
|
||||
|
||||
use super::{load_program, perf_attach, LinkRef, ProgramData, ProgramError};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum SamplePolicy {
|
||||
Period(u64),
|
||||
Frequency(u64),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
pub enum PerfEventScope {
|
||||
CallingProcessAnyCpu,
|
||||
CallingProcessOneCpu { cpu: u32 },
|
||||
OneProcessAnyCpu { pid: u32 },
|
||||
OneProcessOneCpu { cpu: u32, pid: u32 },
|
||||
AllProcessesOneCpu { cpu: u32 },
|
||||
}
|
||||
|
||||
/// A program that can be attached at a perf event.
|
||||
///
|
||||
/// TODO: Explain the different types of perf events and how to get a list.
|
||||
/// Maybe just link to the man page of `perf list`.
|
||||
/// (But it's not clear to me how to translate those strings into numbers.)
|
||||
///
|
||||
/// # Minimum kernel version
|
||||
///
|
||||
/// TODO: minimum kernel version?
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # #[derive(Debug, thiserror::Error)]
|
||||
/// # enum Error {
|
||||
/// # #[error(transparent)]
|
||||
/// # IO(#[from] std::io::Error),
|
||||
/// # #[error(transparent)]
|
||||
/// # Map(#[from] aya::maps::MapError),
|
||||
/// # #[error(transparent)]
|
||||
/// # Program(#[from] aya::programs::ProgramError),
|
||||
/// # #[error(transparent)]
|
||||
/// # Bpf(#[from] aya::BpfError)
|
||||
/// # }
|
||||
/// # let mut bpf = aya::Bpf::load(&[], None)?;
|
||||
/// use std::convert::TryInto;
|
||||
/// use aya::programs::{PerfEvent, PerfEventScope, SamplePolicy };
|
||||
/// use aya::util::online_cpus;
|
||||
///
|
||||
/// let prog: &mut PerfEvent = bpf.program_mut("observe_cpu_clock")?.try_into()?;
|
||||
/// prog.load()?;
|
||||
///
|
||||
/// for cpu in online_cpus()? {
|
||||
/// prog.attach(
|
||||
/// 1, /* PERF_TYPE_SOFTWARE */
|
||||
/// 0, /* PERF_COUNT_SW_CPU_CLOCK */
|
||||
/// PerfEventScope::AllProcessesOneCpu { cpu },
|
||||
/// SamplePolicy::Period(1000000),
|
||||
/// )?;
|
||||
/// }
|
||||
/// # Ok::<(), Error>(())
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
#[doc(alias = "BPF_PROG_TYPE_PERF_EVENT")]
|
||||
pub struct PerfEvent {
|
||||
pub(crate) data: ProgramData,
|
||||
}
|
||||
|
||||
impl PerfEvent {
|
||||
/// Loads the program inside the kernel.
|
||||
///
|
||||
/// See also [`Program::load`](crate::programs::Program::load).
|
||||
pub fn load(&mut self) -> Result<(), ProgramError> {
|
||||
load_program(BPF_PROG_TYPE_PERF_EVENT, &mut self.data)
|
||||
}
|
||||
|
||||
/// Attaches to a given perf event.
|
||||
pub fn attach(
|
||||
&mut self,
|
||||
perf_type: u32, // perf_type_id
|
||||
config: u64,
|
||||
scope: PerfEventScope,
|
||||
sample_policy: SamplePolicy,
|
||||
) -> Result<LinkRef, ProgramError> {
|
||||
let (sample_period, sample_frequency) = match sample_policy {
|
||||
SamplePolicy::Period(period) => (period, None),
|
||||
SamplePolicy::Frequency(frequency) => (0, Some(frequency)),
|
||||
};
|
||||
let (pid, cpu) = match scope {
|
||||
PerfEventScope::CallingProcessAnyCpu => (0, -1),
|
||||
PerfEventScope::CallingProcessOneCpu { cpu } => (0, cpu as i32),
|
||||
PerfEventScope::OneProcessAnyCpu { pid } => (pid as i32, -1),
|
||||
PerfEventScope::OneProcessOneCpu { cpu, pid } => (pid as i32, cpu as i32),
|
||||
PerfEventScope::AllProcessesOneCpu { cpu } => (-1, cpu as i32),
|
||||
};
|
||||
let fd = perf_event_open(
|
||||
perf_type,
|
||||
config,
|
||||
pid,
|
||||
cpu,
|
||||
sample_period,
|
||||
sample_frequency,
|
||||
false,
|
||||
0,
|
||||
)
|
||||
.map_err(|(_code, io_error)| ProgramError::SyscallError {
|
||||
call: "perf_event_open".to_owned(),
|
||||
io_error,
|
||||
})? as i32;
|
||||
|
||||
perf_attach(&mut self.data, fd)
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
use crate::BpfContext;
|
||||
use core::ffi::c_void;
|
||||
|
||||
pub struct PerfEventContext {
|
||||
ctx: *mut c_void,
|
||||
}
|
||||
|
||||
impl PerfEventContext {
|
||||
pub fn new(ctx: *mut c_void) -> PerfEventContext {
|
||||
PerfEventContext { ctx }
|
||||
}
|
||||
}
|
||||
|
||||
impl BpfContext for PerfEventContext {
|
||||
fn as_ptr(&self) -> *mut c_void {
|
||||
self.ctx
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue