|
|
|
@ -1,29 +1,18 @@
|
|
|
|
|
use std::{
|
|
|
|
|
convert::TryFrom,
|
|
|
|
|
ffi::c_void,
|
|
|
|
|
io, mem,
|
|
|
|
|
ops::DerefMut,
|
|
|
|
|
os::unix::prelude::AsRawFd,
|
|
|
|
|
ptr, slice,
|
|
|
|
|
sync::{
|
|
|
|
|
atomic::{self, AtomicPtr, Ordering},
|
|
|
|
|
Arc,
|
|
|
|
|
},
|
|
|
|
|
sync::atomic::{self, AtomicPtr, Ordering},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
use bytes::BytesMut;
|
|
|
|
|
use libc::{
|
|
|
|
|
c_int, close, munmap, sysconf, MAP_FAILED, MAP_SHARED, PROT_READ, PROT_WRITE, _SC_PAGESIZE,
|
|
|
|
|
};
|
|
|
|
|
use libc::{c_int, close, munmap, MAP_FAILED, MAP_SHARED, PROT_READ, PROT_WRITE};
|
|
|
|
|
use thiserror::Error;
|
|
|
|
|
|
|
|
|
|
use crate::{
|
|
|
|
|
generated::{
|
|
|
|
|
bpf_map_type::BPF_MAP_TYPE_PERF_EVENT_ARRAY, perf_event_header, perf_event_mmap_page,
|
|
|
|
|
perf_event_type::*,
|
|
|
|
|
},
|
|
|
|
|
maps::{Map, MapError, MapLockWriteGuard},
|
|
|
|
|
sys::{bpf_map_update_elem, perf_event_ioctl, perf_event_open},
|
|
|
|
|
generated::{perf_event_header, perf_event_mmap_page, perf_event_type::*},
|
|
|
|
|
sys::{perf_event_ioctl, perf_event_open},
|
|
|
|
|
RawFd, PERF_EVENT_IOC_DISABLE, PERF_EVENT_IOC_ENABLE,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@ -66,7 +55,7 @@ pub struct Events {
|
|
|
|
|
pub lost: usize,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct PerfBuffer {
|
|
|
|
|
pub(crate) struct PerfBuffer {
|
|
|
|
|
buf: AtomicPtr<perf_event_mmap_page>,
|
|
|
|
|
size: usize,
|
|
|
|
|
page_size: usize,
|
|
|
|
@ -74,7 +63,7 @@ struct PerfBuffer {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl PerfBuffer {
|
|
|
|
|
fn open(
|
|
|
|
|
pub(crate) fn open(
|
|
|
|
|
cpu_id: u32,
|
|
|
|
|
page_size: usize,
|
|
|
|
|
page_count: usize,
|
|
|
|
@ -259,98 +248,6 @@ impl Drop for PerfBuffer {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Error, Debug)]
|
|
|
|
|
pub enum PerfMapError {
|
|
|
|
|
#[error("error parsing /sys/devices/system/cpu/online")]
|
|
|
|
|
InvalidOnlineCpuFile,
|
|
|
|
|
|
|
|
|
|
#[error("no CPUs specified")]
|
|
|
|
|
NoCpus,
|
|
|
|
|
|
|
|
|
|
#[error("invalid cpu {cpu_id}")]
|
|
|
|
|
InvalidCpu { cpu_id: u32 },
|
|
|
|
|
|
|
|
|
|
#[error("map error: {0}")]
|
|
|
|
|
MapError(#[from] MapError),
|
|
|
|
|
|
|
|
|
|
#[error("perf buffer error: {0}")]
|
|
|
|
|
PerfBufferError(#[from] PerfBufferError),
|
|
|
|
|
|
|
|
|
|
#[error(transparent)]
|
|
|
|
|
IOError(#[from] io::Error),
|
|
|
|
|
|
|
|
|
|
#[error("bpf_map_update_elem failed: {io_error}")]
|
|
|
|
|
UpdateElementError {
|
|
|
|
|
#[source]
|
|
|
|
|
io_error: io::Error,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct PerfMapBuffer<T: DerefMut<Target = Map>> {
|
|
|
|
|
_map: Arc<T>,
|
|
|
|
|
buf: PerfBuffer,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T: DerefMut<Target = Map>> PerfMapBuffer<T> {
|
|
|
|
|
pub fn read_events(&mut self, buffers: &mut [BytesMut]) -> Result<Events, PerfBufferError> {
|
|
|
|
|
self.buf.read_events(buffers)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T: DerefMut<Target = Map>> AsRawFd for PerfMapBuffer<T> {
|
|
|
|
|
fn as_raw_fd(&self) -> RawFd {
|
|
|
|
|
self.buf.as_raw_fd()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct PerfMap<T: DerefMut<Target = Map>> {
|
|
|
|
|
map: Arc<T>,
|
|
|
|
|
page_size: usize,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T: DerefMut<Target = Map>> PerfMap<T> {
|
|
|
|
|
pub fn new(map: T) -> Result<PerfMap<T>, PerfMapError> {
|
|
|
|
|
let map_type = map.obj.def.map_type;
|
|
|
|
|
if map_type != BPF_MAP_TYPE_PERF_EVENT_ARRAY {
|
|
|
|
|
return Err(MapError::InvalidMapType {
|
|
|
|
|
map_type: map_type as u32,
|
|
|
|
|
})?;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(PerfMap {
|
|
|
|
|
map: Arc::new(map),
|
|
|
|
|
// Safety: libc
|
|
|
|
|
page_size: unsafe { sysconf(_SC_PAGESIZE) } as usize,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn open(
|
|
|
|
|
&mut self,
|
|
|
|
|
index: u32,
|
|
|
|
|
page_count: Option<usize>,
|
|
|
|
|
) -> Result<PerfMapBuffer<T>, PerfMapError> {
|
|
|
|
|
// FIXME: keep track of open buffers
|
|
|
|
|
|
|
|
|
|
let map_fd = self.map.fd_or_err()?;
|
|
|
|
|
let buf = PerfBuffer::open(index, self.page_size, page_count.unwrap_or(2))?;
|
|
|
|
|
bpf_map_update_elem(map_fd, &index, &buf.fd, 0)
|
|
|
|
|
.map_err(|(_, io_error)| PerfMapError::UpdateElementError { io_error })?;
|
|
|
|
|
|
|
|
|
|
Ok(PerfMapBuffer {
|
|
|
|
|
buf,
|
|
|
|
|
_map: self.map.clone(),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl TryFrom<MapLockWriteGuard> for PerfMap<MapLockWriteGuard> {
|
|
|
|
|
type Error = PerfMapError;
|
|
|
|
|
|
|
|
|
|
fn try_from(a: MapLockWriteGuard) -> Result<PerfMap<MapLockWriteGuard>, PerfMapError> {
|
|
|
|
|
PerfMap::new(a)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg_attr(test, allow(unused_variables))]
|
|
|
|
|
unsafe fn mmap(
|
|
|
|
|
addr: *mut c_void,
|