Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,27 @@
// You should have received a copy of the GNU Lesser General Public License along with Perf-event-rs. If not,
// see <https://www.gnu.org/licenses/>.

use std::{mem::size_of, ops::Not};

#[cfg(feature = "linux-4.1")]
use libc::{CLOCK_BOOTTIME, CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW, CLOCK_REALTIME, CLOCK_TAI};
use std::ops::Not;

use crate::perf_event::PerfEventAttr;
#[cfg(feature = "linux-4.1")]
use crate::sampling::ClockId;
use crate::{
perf_event::PerfEventAttr,
sampling::{Config, ExtraConfig, OverflowBy, SampleIpSkid, Wakeup},
syscall::bindings::*,
Event, EventScope, RawPerfEventAttr,
};
use crate::sampling::{EventConfig, OverflowBy, SampleIpSkid, SamplerConfig, Wakeup};
use crate::syscall::bindings::*;
#[cfg(feature = "linux-4.17")]
use crate::{DynamicPmuEvent, KprobeConfig, UprobeConfig};
use crate::{Event, EventScope, RawPerfEventAttr};
#[cfg(feature = "linux-4.1")]
use libc::{CLOCK_BOOTTIME, CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW, CLOCK_REALTIME, CLOCK_TAI};

#[inline]
pub fn new<'t>(
pub fn build<'t>(
event: &Event,
scopes: impl IntoIterator<Item = &'t EventScope>,
overflow_by: &OverflowBy,
extra_config: &ExtraConfig,
) -> Config {
let sample_record_fields = &extra_config.sample_record_fields;
sampler_config: &SamplerConfig,
) -> EventConfig {
let sample_fields = &sampler_config.sample_fields;

let mut perf_event_attr = PerfEventAttr(RawPerfEventAttr {
type_: 0,
Expand All @@ -45,7 +42,7 @@ pub fn new<'t>(
OverflowBy::Freq(f) => perf_event_attr__bindgen_ty_1 { sample_freq: *f },
OverflowBy::Period(p) => perf_event_attr__bindgen_ty_1 { sample_period: *p },
},
sample_type: sample_record_fields.as_sample_type(),
sample_type: sample_fields.as_sample_type(),
read_format: {
#[allow(unused_mut)]
#[allow(clippy::identity_op)] // for readable
Expand All @@ -65,7 +62,7 @@ pub fn new<'t>(
_bitfield_align_1: [],
// set later via perf_event_attr.set_...
_bitfield_1: __BindgenBitfieldUnit::new([0u8; 8usize]),
__bindgen_anon_2: match &extra_config.wakeup {
__bindgen_anon_2: match &sampler_config.wakeup {
Wakeup::Events(val) => perf_event_attr__bindgen_ty_2 {
wakeup_events: *val,
},
Expand All @@ -80,30 +77,30 @@ pub fn new<'t>(
__bindgen_anon_4: perf_event_attr__bindgen_ty_4::default(),

branch_sample_type: 0, // TODO: Not all hardware supports this feature
sample_regs_user: sample_record_fields.abi_and_regs_user.unwrap_or(0),
sample_stack_user: sample_record_fields.data_stack_user.unwrap_or(0) as _,
sample_regs_user: sample_fields.abi_and_regs_user.unwrap_or(0),
sample_stack_user: sample_fields.data_stack_user.unwrap_or(0) as _,
#[rustfmt::skip]
#[cfg(feature = "linux-4.1")]
clockid: extra_config.clockid.as_ref().map_or(0, |id| match id {
clockid: sampler_config.clockid.as_ref().map_or(0, |id| match id {
ClockId::Monotonic => CLOCK_MONOTONIC,
ClockId::MonotonicRaw => CLOCK_MONOTONIC_RAW,
ClockId::RealTime => CLOCK_REALTIME,
ClockId::BootTime => CLOCK_BOOTTIME,
ClockId::Tai => CLOCK_TAI,
}) as _,
#[cfg(feature = "linux-3.19")]
sample_regs_intr: sample_record_fields.abi_and_regs_intr.unwrap_or(0),
sample_regs_intr: sample_fields.abi_and_regs_intr.unwrap_or(0),
#[cfg(feature = "linux-4.1")]
aux_watermark: 0, // TODO
#[cfg(feature = "linux-4.8")]
sample_max_stack: sample_record_fields.ips.unwrap_or(0),
sample_max_stack: sample_fields.ips.unwrap_or(0),
__reserved_2: 0,
#[cfg(feature = "linux-5.5")]
aux_sample_size: 0, // TODO
#[cfg(feature = "linux-5.5")]
__reserved_3: 0,
#[cfg(feature = "linux-5.13")]
sig_data: extra_config.sigtrap.unwrap_or(0),
sig_data: sampler_config.sigtrap.unwrap_or(0),

// TODO: https://github.com/torvalds/linux/commit/09519ec3b19e4144b5f6e269c54fbb9c294a9fcb
#[cfg(feature = "linux-6.3")]
Expand All @@ -118,37 +115,38 @@ pub fn new<'t>(
create a performance issue due to all children writing to the
same rb.
*/
perf_event_attr.set_inherit(extra_config.inherit as _);
perf_event_attr.set_pinned(extra_config.pinned as _);
perf_event_attr.set_exclusive(extra_config.exclusive as _);
perf_event_attr.set_inherit(sampler_config.inherit as _);
perf_event_attr.set_pinned(sampler_config.pinned as _);
perf_event_attr.set_exclusive(sampler_config.exclusive as _);

perf_event_attr.set_exclude_user(1);
perf_event_attr.set_exclude_kernel(1);
perf_event_attr.set_exclude_hv(1);
perf_event_attr.set_exclude_idle(1);

perf_event_attr.set_mmap(0);
perf_event_attr.set_comm(extra_config.comm as _);
perf_event_attr.set_comm(sampler_config.comm as _);
perf_event_attr.set_freq(match overflow_by {
OverflowBy::Freq(_) => 1,
OverflowBy::Period(_) => 0,
});
perf_event_attr.set_inherit_stat(extra_config.inherit_stat as _); // `inherit_stat` requires `inherit` to be enabled
perf_event_attr.set_enable_on_exec(extra_config.enable_on_exec as _);
perf_event_attr.set_inherit_stat(sampler_config.inherit_stat as _); // `inherit_stat` requires `inherit` to be enabled
perf_event_attr.set_enable_on_exec(sampler_config.enable_on_exec as _);
perf_event_attr.set_task(0);
perf_event_attr.set_watermark(match extra_config.wakeup {
perf_event_attr.set_watermark(match sampler_config.wakeup {
Wakeup::Watermark(_) => 1,
Wakeup::Events(_) => 0,
});
perf_event_attr.set_precise_ip(match extra_config.precise_ip {
perf_event_attr.set_precise_ip(match sampler_config.precise_ip {
SampleIpSkid::Arbitrary => 0,
SampleIpSkid::Constant => 1,
SampleIpSkid::TryZero => 2,
SampleIpSkid::Zero => 3,
});
perf_event_attr.set_mmap_data(extra_config.mmap_data as _);
perf_event_attr.set_mmap_data(sampler_config.mmap_data as _);

if extra_config.extra_record_with_sample_id && extra_config.extra_record_types.is_empty().not()
if sampler_config.side_band_record_with_sample_id
&& sampler_config.side_band_records.is_empty().not()
{
perf_event_attr.set_sample_id_all(1);
} else {
Expand All @@ -158,15 +156,16 @@ pub fn new<'t>(
perf_event_attr.set_exclude_host(1);
perf_event_attr.set_exclude_guest(1);

perf_event_attr.set_exclude_callchain_kernel(extra_config.include_callchain_kernel.not() as _);
perf_event_attr.set_exclude_callchain_user(extra_config.include_callchain_user.not() as _);
perf_event_attr
.set_exclude_callchain_kernel(sampler_config.include_callchain_kernel.not() as _);
perf_event_attr.set_exclude_callchain_user(sampler_config.include_callchain_user.not() as _);

#[cfg(feature = "linux-3.12")]
perf_event_attr.set_mmap2(0);
#[cfg(feature = "linux-3.16")]
perf_event_attr.set_comm_exec(extra_config.comm_exec as _);
perf_event_attr.set_comm_exec(sampler_config.comm_exec as _);
#[cfg(feature = "linux-4.1")]
perf_event_attr.set_use_clockid(extra_config.clockid.is_some() as _);
perf_event_attr.set_use_clockid(sampler_config.clockid.is_some() as _);
#[cfg(feature = "linux-4.3")]
perf_event_attr.set_context_switch(0);
#[cfg(feature = "linux-4.7")]
Expand All @@ -185,22 +184,22 @@ pub fn new<'t>(
#[cfg(feature = "linux-5.9")]
perf_event_attr.set_text_poke(0);
#[cfg(feature = "linux-5.12")]
perf_event_attr.set_build_id(extra_config.build_id as _);
perf_event_attr.set_build_id(sampler_config.build_id as _);
#[cfg(feature = "linux-5.13")]
perf_event_attr.set_inherit_thread(extra_config.inherit_thread as _);
perf_event_attr.set_inherit_thread(sampler_config.inherit_thread as _);
#[cfg(feature = "linux-5.13")]
perf_event_attr.set_remove_on_exec(extra_config.remove_on_exec as _);
perf_event_attr.set_remove_on_exec(sampler_config.remove_on_exec as _);
#[cfg(feature = "linux-5.13")]
perf_event_attr.set_sigtrap(extra_config.sigtrap.is_some() as _);
perf_event_attr.set_sigtrap(sampler_config.sigtrap.is_some() as _);

event.enable_in_raw_attr(&mut perf_event_attr);

scopes
.into_iter()
.for_each(|scope| scope.enable_in_raw_attr(&mut perf_event_attr));

extra_config
.extra_record_types
sampler_config
.side_band_records
.iter()
.for_each(|it| it.enable_in_raw_attr(&mut perf_event_attr));

Expand All @@ -218,7 +217,7 @@ pub fn new<'t>(
_ => None,
};

Config {
EventConfig {
kprobe_func_or_uprobe_path,
perf_event_attr,
}
Expand Down
26 changes: 13 additions & 13 deletions src/perf_event/sampling/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@
// You should have received a copy of the GNU Lesser General Public License along with Perf-event-rs. If not,
// see <https://www.gnu.org/licenses/>.

mod extra_config;
mod extra_record;
mod new;
mod sample_record_fields;
mod builder;
mod sample_fields;
mod sampler_config;
mod side_band_record;

use std::{ffi::CString, fmt::Debug, rc::Rc};

pub use extra_config::*;
pub use extra_record::*;
pub use sample_record_fields::*;
pub use sample_fields::*;
pub use sampler_config::*;
pub use side_band_record::*;

use crate::{perf_event::PerfEventAttr, Event, EventScope};

Expand All @@ -32,29 +32,29 @@ pub enum OverflowBy {
}

#[derive(Debug, Clone)]
pub struct Config {
pub struct EventConfig {
// This will keep the ptr of `kprobe_func` or `uprobe_path` valid if present.
#[allow(dead_code)]
kprobe_func_or_uprobe_path: Option<Rc<CString>>,
perf_event_attr: PerfEventAttr,
}

impl Config {
impl EventConfig {
pub fn new<'t>(
event: &Event,
scopes: impl IntoIterator<Item = &'t EventScope>,
overflow_by: &OverflowBy,
) -> Self {
Self::extra_new(event, scopes, overflow_by, &Default::default())
Self::new_with_sampler_config(event, scopes, overflow_by, &Default::default())
}

pub fn extra_new<'t>(
pub fn new_with_sampler_config<'t>(
event: &Event,
scopes: impl IntoIterator<Item = &'t EventScope>,
overflow_by: &OverflowBy,
extra_config: &ExtraConfig,
sampler_config: &SamplerConfig,
) -> Self {
new::new(event, scopes, overflow_by, extra_config)
builder::build(event, scopes, overflow_by, sampler_config)
}

/// Construct from a `PerfEventAttr` struct.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::{sampling::record::sample::WeightRepr, syscall::bindings::*};

/// Select the fields contained in `sample::Body`
#[derive(Debug, Clone, Default)]
pub struct SampleRecordFields {
pub struct SampleFields {
#[cfg(feature = "linux-3.12")]
pub sample_id: bool, // PERF_SAMPLE_IDENTIFIER
pub ip: bool, // PERF_SAMPLE_IP
Expand All @@ -27,7 +27,7 @@ pub struct SampleRecordFields {
pub stream_id: bool, // PERF_SAMPLE_STREAM_ID
pub cpu: bool, // PERF_SAMPLE_CPU
pub period: bool, // PERF_SAMPLE_PERIOD
pub v: bool, // PERF_SAMPLE_READ
pub read: bool, // PERF_SAMPLE_READ

/// Wrap `sample_max_stack` with `Some` to enable this field
pub ips: Option<u16>, // PERF_SAMPLE_CALLCHAIN
Expand Down Expand Up @@ -82,7 +82,7 @@ pub struct SampleRecordFields {
pub code_page_size: bool, // PERF_SAMPLE_CODE_PAGE_SIZE
}

impl SampleRecordFields {
impl SampleFields {
#[allow(clippy::cognitive_complexity)]
pub(crate) const fn as_sample_type(&self) -> u64 {
macro_rules! gen {
Expand Down Expand Up @@ -115,7 +115,7 @@ impl SampleRecordFields {
self.stream_id , PERF_SAMPLE_STREAM_ID
self.cpu , PERF_SAMPLE_CPU
self.period , PERF_SAMPLE_PERIOD
self.v , PERF_SAMPLE_READ
self.read , PERF_SAMPLE_READ
self.ips.is_some() , PERF_SAMPLE_CALLCHAIN
self.data_raw , PERF_SAMPLE_RAW
// TODO: Not all hw supports PERF_SAMPLE_BRANCH_STACK
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@
// You should have received a copy of the GNU Lesser General Public License along with Perf-event-rs. If not,
// see <https://www.gnu.org/licenses/>.

use crate::sampling::{
config::sample_record_fields::SampleRecordFields, ExtraRecord, Wakeup::Events,
};
use crate::sampling::config::sample_fields::SampleFields;
use crate::sampling::SideBandRecord;
use crate::sampling::Wakeup::Events;

#[derive(Debug, Clone)]
pub struct ExtraConfig {
pub struct SamplerConfig {
pub pinned: bool,
pub exclusive: bool,
pub mmap_data: bool,
Expand All @@ -26,7 +26,7 @@ pub struct ExtraConfig {
#[cfg(feature = "linux-3.16")]
pub comm_exec: bool,

/// TODO: `inherit` can't be turned on when `sample_record_fields.v` is enabled
/// TODO: `inherit` can't be turned on when `sample_fields.read` is enabled
pub inherit: bool,
pub inherit_stat: bool,
pub inherit_thread: bool,
Expand All @@ -50,14 +50,14 @@ pub struct ExtraConfig {
/// Wrap `sig_data` with `Some` to enable sigtrap
pub sigtrap: Option<u64>,

pub sample_record_fields: SampleRecordFields,
pub sample_fields: SampleFields,

pub extra_record_types: Vec<ExtraRecord>,
pub side_band_records: Vec<SideBandRecord>,
/// i.e. `sample_id_all`
pub extra_record_with_sample_id: bool,
pub side_band_record_with_sample_id: bool,
}

impl Default for ExtraConfig {
impl Default for SamplerConfig {
fn default() -> Self {
Self {
pinned: false,
Expand Down Expand Up @@ -90,10 +90,10 @@ impl Default for ExtraConfig {
wakeup: Events(1),
sigtrap: None,

sample_record_fields: Default::default(),
sample_fields: Default::default(),

extra_record_types: vec![],
extra_record_with_sample_id: false,
side_band_records: vec![],
side_band_record_with_sample_id: false,
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@

use std::ops::Not;

use crate::perf_event::PerfEventAttr;
use crate::PerfEventAttr;

/// TODO: this SideBandRecord doesn't include all
/// the side-band record types here. E.g., comm,
/// comm should be coded as a side-band record.
#[derive(PartialEq, Eq, Clone, Debug)]
pub enum ExtraRecord {
pub enum SideBandRecord {
Mmap,

// `PERF_RECORD_MMAP2` was first added to the Linux kernel in 3.12
Expand Down Expand Up @@ -59,7 +62,7 @@ pub enum ExtraRecord {
ForkAndExit,
}

impl ExtraRecord {
impl SideBandRecord {
pub fn all() -> Vec<Self> {
vec![
Self::Mmap,
Expand Down
Loading
Loading