diff --git a/crates/op/host-op-perf/src/convert/config.rs b/crates/op/host-op-perf/src/convert/config.rs index 06a6ed7..417e8d1 100644 --- a/crates/op/host-op-perf/src/convert/config.rs +++ b/crates/op/host-op-perf/src/convert/config.rs @@ -17,11 +17,15 @@ use std::io; use perf_event_rs::{ EventScope as RawEvScope, config, config::{Cpu as RawCpu, Process as RawProcess}, - counting::{Config as RawConfig, Counter, CounterStat, ExtraConfig as RawExtraConfig}, + counting::{Config as RawConfig, Counter, CounterStat, ExtraConfig as CountExtraConfig}, event::Event as RawEv, + sampling::ExtraConfig as SampleExtraConfig, }; -use crate::convert::{Error, Wrap}; +use crate::{ + convert::{Error, Wrap}, + profiling::perf::config::OverflowBy, +}; type FromT = crate::profiling::perf::config::Config; type IntoT = perf_event_rs::counting::Config; @@ -36,8 +40,38 @@ impl TryFrom<&FromT> for Wrap { .map(|it| Wrap::::from(it).into_inner()) .collect(); let event = Wrap::::try_from(&value.event)?.into_inner(); - let extra_config = Wrap::::try_from(&value.extra_config)?.into_inner(); + let extra_config = Wrap::::try_from(&value.extra_config)?.into_inner(); Ok(Self(RawConfig::extra_new(&event, &scopes, &extra_config))) } } + +impl TryInto for crate::profiling::perf::config::SamplingConfig { + type Error = Error; + + fn try_into(self) -> Result { + let scopes: Vec<_> = self + .scopes + .iter() + .map(|it| Wrap::::from(it).into_inner()) + .collect(); + let event = Wrap::::try_from(&self.event)?.into_inner(); + Ok(perf_event_rs::sampling::Config::extra_new( + &event, + &scopes, + &self.overflow_by.into(), + &self.extra_config.into(), + )) + } +} + +type HostOverflowBy = perf_event_rs::sampling::OverflowBy; + +impl From for HostOverflowBy { + fn from(val: OverflowBy) -> Self { + match val { + OverflowBy::Period(p) => Self::Period(p), + OverflowBy::Freq(f) => Self::Freq(f), + } + } +} diff --git a/crates/op/host-op-perf/src/convert/extra_config.rs b/crates/op/host-op-perf/src/convert/extra_config.rs index ae7a4f0..c8af546 100644 --- a/crates/op/host-op-perf/src/convert/extra_config.rs +++ b/crates/op/host-op-perf/src/convert/extra_config.rs @@ -13,6 +13,10 @@ // see . use crate::convert::Wrap; +use crate::profiling::perf; +use crate::profiling::perf::config::{ + ClockId, SampleIpSkid, SampleRecordFields, Wakeup, WeightRepr, +}; type FromT = crate::profiling::perf::config::ExtraConfig; type IntoT = perf_event_rs::counting::ExtraConfig; @@ -42,3 +46,130 @@ impl TryFrom<&FromT> for Wrap { Ok(Self(val)) } } + +impl From + for perf_event_rs::sampling::ExtraConfig +{ + fn from(val: crate::profiling::perf::config::SamplingExtraConfig) -> Self { + Self { + pinned: val.pinned, + exclusive: val.exclusive, + mmap_data: val.mmap_data, + comm: val.comm, + comm_exec: val.comm_exec, + inherit: val.inherit, + inherit_stat: val.inherit_stat, + inherit_thread: val.inherit_thread, + build_id: val.build_id, + enable_on_exec: val.enable_on_exec, + remove_on_exec: val.remove_on_exec, + include_callchain_kernel: val.include_callchain_kernel, + include_callchain_user: val.include_callchain_user, + clockid: val.clockid.map(Into::into), + precise_ip: val.precise_ip.into(), + wakeup: val.wakeup.into(), + sigtrap: val.sigtrap, + sample_record_fields: val.sample_record_fields.into(), + extra_record_types: val.extra_record_types.into_iter().map(Into::into).collect(), + extra_record_with_sample_id: val.extra_record_with_sample_id, + } + } +} + +type HostExtraRecord = perf_event_rs::sampling::ExtraRecord; + +impl From for HostExtraRecord { + fn from(val: crate::profiling::perf::config::ExtraRecord) -> Self { + match val { + perf::config::ExtraRecord::Mmap => Self::Mmap, + perf::config::ExtraRecord::Mmap2 => Self::Mmap2, + perf::config::ExtraRecord::ContextSwitch => Self::ContextSwitch, + perf::config::ExtraRecord::Namespaces => Self::Namespaces, + perf::config::ExtraRecord::Ksymbol => Self::Ksymbol, + perf::config::ExtraRecord::BpfEvent => Self::BpfEvent, + perf::config::ExtraRecord::Cgroup => Self::Cgroup, + perf::config::ExtraRecord::TextPoke => Self::TextPoke, + perf::config::ExtraRecord::ForkAndExit => Self::ForkAndExit, + } + } +} + +type HostWeightRepr = perf_event_rs::sampling::record::sample::WeightRepr; + +impl From for HostWeightRepr { + fn from(val: WeightRepr) -> Self { + match val { + WeightRepr::Full => Self::Full, + WeightRepr::Vars => Self::Vars, + } + } +} + +type HostSampleRecordFields = perf_event_rs::sampling::SampleRecordFields; + +impl From for HostSampleRecordFields { + fn from(val: SampleRecordFields) -> Self { + HostSampleRecordFields { + sample_id: val.sample_id, + ip: val.ip, + pid_and_tid: val.pid_and_tid, + time: val.time, + addr: val.addr, + id: val.id, + stream_id: val.stream_id, + cpu: val.cpu, + period: val.period, + v: val.v, + ips: val.ips, + data_raw: val.data_raw, + abi_and_regs_user: val.abi_and_regs_user, + data_stack_user: val.data_stack_user, + weight: val.weight.map(Into::into), + data_src: val.data_src, + transaction: val.transaction, + abi_and_regs_intr: val.abi_and_regs_intr, + phys_addr: val.phys_addr, + cgroup: val.cgroup, + data_page_size: val.data_page_size, + code_page_size: val.code_page_size, + } + } +} + +type HostWakeup = perf_event_rs::sampling::Wakeup; + +impl From for HostWakeup { + fn from(val: Wakeup) -> Self { + match val { + Wakeup::Events(e) => Self::Events(e), + Wakeup::Watermark(w) => Self::Watermark(w), + } + } +} + +type HostSampleIpSkid = perf_event_rs::sampling::SampleIpSkid; + +impl From for HostSampleIpSkid { + fn from(val: SampleIpSkid) -> Self { + match val { + SampleIpSkid::Arbitrary => Self::Arbitrary, + SampleIpSkid::Constant => Self::Constant, + SampleIpSkid::TryZero => Self::TryZero, + SampleIpSkid::Zero => Self::Zero, + } + } +} + +type HostClockId = perf_event_rs::sampling::ClockId; + +impl From for HostClockId { + fn from(val: ClockId) -> Self { + match val { + ClockId::Monotonic => Self::Monotonic, + ClockId::MonotonicRaw => Self::MonotonicRaw, + ClockId::RealTime => Self::RealTime, + ClockId::BootTime => Self::BootTime, + ClockId::Tai => Self::Tai, + } + } +} diff --git a/crates/op/host-op-perf/src/convert/mod.rs b/crates/op/host-op-perf/src/convert/mod.rs index eca7779..e116c4f 100644 --- a/crates/op/host-op-perf/src/convert/mod.rs +++ b/crates/op/host-op-perf/src/convert/mod.rs @@ -20,6 +20,7 @@ mod event; mod event_scope; mod extra_config; mod process; +mod sample_record; mod stat; pub use config::*; diff --git a/crates/op/host-op-perf/src/convert/sample_record.rs b/crates/op/host-op-perf/src/convert/sample_record.rs new file mode 100644 index 0000000..51ee815 --- /dev/null +++ b/crates/op/host-op-perf/src/convert/sample_record.rs @@ -0,0 +1,575 @@ +use std::collections::HashMap; +use std::ffi::CString; + +use crate::profiling::perf::sampler::{AnonNormal, AuxOutputHwIdBody, WeightVars}; + +impl From for crate::profiling::perf::sampler::Record { + fn from(value: perf_event_rs::sampling::record::Record) -> Self { + Self { + misc: value.misc, + body: value.body.into(), + } + } +} + +impl From + for crate::profiling::perf::sampler::RecordBody +{ + fn from(value: perf_event_rs::sampling::record::RecordBody) -> Self { + match value { + perf_event_rs::sampling::record::RecordBody::Mmap(mmap_body) => { + Self::Mmap((*mmap_body).into()) + } + perf_event_rs::sampling::record::RecordBody::Lost(lost_body) => { + Self::Lost((*lost_body).into()) + } + perf_event_rs::sampling::record::RecordBody::Comm(comm_body) => { + Self::Comm((*comm_body).into()) + } + perf_event_rs::sampling::record::RecordBody::Exit(exit_body) => { + Self::Exit((*exit_body).into()) + } + perf_event_rs::sampling::record::RecordBody::Throttle(throttle_body) => { + Self::Throttle((*throttle_body).into()) + } + perf_event_rs::sampling::record::RecordBody::Unthrottle(throttle_body) => { + Self::Unthrottle((*throttle_body).into()) + } + perf_event_rs::sampling::record::RecordBody::Fork(fork_body) => { + Self::Fork((*fork_body).into()) + } + perf_event_rs::sampling::record::RecordBody::Read(read_body) => { + Self::Read((*read_body).into()) + } + perf_event_rs::sampling::record::RecordBody::Sample(sample_body) => { + Self::Sample((*sample_body).into()) + } + perf_event_rs::sampling::record::RecordBody::Mmap2(mmap2_body) => { + Self::Mmap2((*mmap2_body).into()) + } + perf_event_rs::sampling::record::RecordBody::Aux(aux_body) => { + Self::Aux((*aux_body).into()) + } + perf_event_rs::sampling::record::RecordBody::ItraceStart(intrace_start_body) => { + Self::ItraceStart((*intrace_start_body).into()) + } + perf_event_rs::sampling::record::RecordBody::LostSamples(lost_samples_body) => { + Self::LostSamples((*lost_samples_body).into()) + } + perf_event_rs::sampling::record::RecordBody::Switch(switch_body) => { + Self::Switch((*switch_body).into()) + } + perf_event_rs::sampling::record::RecordBody::SwitchCpuWide(switch_cpu_wide_body) => { + Self::SwitchCpuWide((*switch_cpu_wide_body).into()) + } + perf_event_rs::sampling::record::RecordBody::Namespaces(namespaces_body) => { + Self::Namespaces((*namespaces_body).into()) + } + perf_event_rs::sampling::record::RecordBody::Ksymbol(ksymbol_body) => { + Self::Ksymbol((*ksymbol_body).into()) + } + perf_event_rs::sampling::record::RecordBody::BpfEvent(bpf_event_body) => { + Self::BpfEvent((*bpf_event_body).into()) + } + perf_event_rs::sampling::record::RecordBody::Cgroup(cgroup_body) => { + Self::Cgroup((*cgroup_body).into()) + } + perf_event_rs::sampling::record::RecordBody::TextPoke(text_poke_body) => { + Self::TextPoke((*text_poke_body).into()) + } + perf_event_rs::sampling::record::RecordBody::AuxOutputHwId(_body) => { + Self::AuxOutputHwId(AuxOutputHwIdBody {}) + } + } + } +} + +impl From + for crate::profiling::perf::sampler::TextPokeBody +{ + fn from(value: perf_event_rs::sampling::record::text_poke::Body) -> Self { + Self { + addr: value.addr, + old_len: value.old_len, + new_len: value.new_len, + bytes: value.bytes, + sample_id: value.sample_id.map(Into::into), + } + } +} + +impl From + for crate::profiling::perf::sampler::CgroupBody +{ + fn from(value: perf_event_rs::sampling::record::cgroup::Body) -> Self { + Self { + id: value.id, + path: value.path.to_string_lossy().into_owned(), + sample_id: value.sample_id.map(Into::into), + } + } +} + +impl From + for crate::profiling::perf::sampler::BpfEventBody +{ + fn from(value: perf_event_rs::sampling::record::bpf_event::Body) -> Self { + Self { + type_: value.r#type, + flags: value.flags, + id: value.id, + tag: value.tag.to_vec(), + sample_id: value.sample_id.map(Into::into), + } + } +} + +impl From + for crate::profiling::perf::sampler::KsymbolBody +{ + fn from(value: perf_event_rs::sampling::record::ksymbol::Body) -> Self { + Self { + addr: value.addr, + len: value.len, + ksym_type: value.ksym_type, + flags: value.flags, + name: value.name.to_string_lossy().into_owned(), + sample_id: value.sample_id.map(Into::into), + } + } +} + +impl From + for crate::profiling::perf::sampler::Namespace +{ + fn from(value: perf_event_rs::sampling::record::namespaces::Namespace) -> Self { + Self { + dev: value.dev, + inode: value.inode, + } + } +} + +impl From + for crate::profiling::perf::sampler::NamespacesBody +{ + fn from(value: perf_event_rs::sampling::record::namespaces::Body) -> Self { + Self { + pid: value.pid, + tid: value.tid, + namespaces: value.namespaces.into_iter().map(Into::into).collect(), + sample_id: value.sample_id.map(Into::into), + } + } +} + +impl From + for crate::profiling::perf::sampler::SwitchCpuWideBody +{ + fn from(value: perf_event_rs::sampling::record::switch_cpu_wide::Body) -> Self { + Self { + next_prev_pid: value.next_prev_pid, + next_prev_tid: value.next_prev_tid, + sample_id: value.sample_id.map(Into::into), + } + } +} + +impl From + for crate::profiling::perf::sampler::SwitchBody +{ + fn from(value: perf_event_rs::sampling::record::switch::Body) -> Self { + Self { + sample_id: value.sample_id.map(Into::into), + } + } +} + +impl From + for crate::profiling::perf::sampler::LostSamplesBody +{ + fn from(value: perf_event_rs::sampling::record::lost_samples::Body) -> Self { + Self { + lost: value.lost, + sample_id: value.sample_id.map(Into::into), + } + } +} + +impl From + for crate::profiling::perf::sampler::IntraceStartBody +{ + fn from(value: perf_event_rs::sampling::record::intrace_start::Body) -> Self { + Self { + pid: value.pid, + tid: value.tid, + } + } +} + +impl From for crate::profiling::perf::sampler::AuxBody { + fn from(value: perf_event_rs::sampling::record::aux::Body) -> Self { + Self { + aux_offset: value.aux_offset, + aux_size: value.aux_size, + flags: value.flags, + sample_id: value.sample_id.map(Into::into), + } + } +} + +impl From + for crate::profiling::perf::sampler::AnonEnum +{ + fn from(value: perf_event_rs::sampling::record::mmap2::AnonEnum) -> Self { + match value { + perf_event_rs::sampling::record::mmap2::AnonEnum::Normal { + maj, + min, + ino, + ino_generation, + } => Self::Normal(AnonNormal { + maj, + min, + ino, + ino_generation, + }), + perf_event_rs::sampling::record::mmap2::AnonEnum::BuildId(vec) => Self::BuildId(vec), + } + } +} + +impl From + for crate::profiling::perf::sampler::Mmap2Body +{ + fn from(value: perf_event_rs::sampling::record::mmap2::Body) -> Self { + Self { + pid: value.pid, + tid: value.tid, + addr: value.addr, + len: value.len, + pgoff: value.pgoff, + anon_enum: value.anon_enum.into(), + prot: value.prot, + flags: value.flags, + filename: value.filename.to_string_lossy().into_owned(), + sample_id: value.sample_id.map(Into::into), + } + } +} + +impl From for crate::profiling::perf::sampler::Abi { + fn from(value: perf_event_rs::sampling::record::sample::Abi) -> Self { + match value { + perf_event_rs::sampling::record::sample::Abi::AbiNone => Self::AbiNone, + perf_event_rs::sampling::record::sample::Abi::Abi32 => Self::Abi32, + perf_event_rs::sampling::record::sample::Abi::Abi64 => Self::Abi64, + } + } +} + +impl From + for crate::profiling::perf::sampler::AbiAndRegs +{ + fn from(value: perf_event_rs::sampling::record::sample::AbiAndRegs) -> Self { + Self { + abi: value.abi.into(), + regs: value.regs, + } + } +} + +impl From + for crate::profiling::perf::sampler::Weight +{ + fn from(value: perf_event_rs::sampling::record::sample::Weight) -> Self { + match value { + perf_event_rs::sampling::record::sample::Weight::Full(f) => Self::Full(f), + perf_event_rs::sampling::record::sample::Weight::Vars { + var1_dw, + var2_w, + var3_w, + } => Self::Vars(WeightVars { + var1_dw, + var2_w, + var3_w, + }), + } + } +} + +impl From + for crate::profiling::perf::sampler::MemOp +{ + fn from(value: perf_event_rs::sampling::record::sample::MemOp) -> Self { + match value { + perf_event_rs::sampling::record::sample::MemOp::Na => Self::Na, + perf_event_rs::sampling::record::sample::MemOp::Load => Self::Load, + perf_event_rs::sampling::record::sample::MemOp::Store => Self::Store, + perf_event_rs::sampling::record::sample::MemOp::Pfetch => Self::Pfetch, + perf_event_rs::sampling::record::sample::MemOp::Exec => Self::Exec, + } + } +} + +impl From + for crate::profiling::perf::sampler::MemLvl +{ + fn from(value: perf_event_rs::sampling::record::sample::MemLvl) -> Self { + match value { + perf_event_rs::sampling::record::sample::MemLvl::Na => Self::Na, + perf_event_rs::sampling::record::sample::MemLvl::Hit => Self::Hit, + perf_event_rs::sampling::record::sample::MemLvl::Miss => Self::Miss, + perf_event_rs::sampling::record::sample::MemLvl::L1 => Self::L1, + perf_event_rs::sampling::record::sample::MemLvl::Lfb => Self::Lfb, + perf_event_rs::sampling::record::sample::MemLvl::L2 => Self::L2, + perf_event_rs::sampling::record::sample::MemLvl::L3 => Self::L3, + perf_event_rs::sampling::record::sample::MemLvl::LocRam => Self::LocRam, + perf_event_rs::sampling::record::sample::MemLvl::RemRam1 => Self::RemRam1, + perf_event_rs::sampling::record::sample::MemLvl::RemRam2 => Self::RemRam2, + perf_event_rs::sampling::record::sample::MemLvl::RemCce1 => Self::RemCce1, + perf_event_rs::sampling::record::sample::MemLvl::RemCce2 => Self::RemCce2, + perf_event_rs::sampling::record::sample::MemLvl::Io => Self::Io, + perf_event_rs::sampling::record::sample::MemLvl::Unc => Self::Unc, + } + } +} + +impl From + for crate::profiling::perf::sampler::MemSnoop +{ + fn from(value: perf_event_rs::sampling::record::sample::MemSnoop) -> Self { + match value { + perf_event_rs::sampling::record::sample::MemSnoop::Na => Self::Na, + perf_event_rs::sampling::record::sample::MemSnoop::None => Self::None, + perf_event_rs::sampling::record::sample::MemSnoop::Hit => Self::Hit, + perf_event_rs::sampling::record::sample::MemSnoop::Miss => Self::Miss, + perf_event_rs::sampling::record::sample::MemSnoop::Hitm => Self::Hitm, + } + } +} +impl From + for crate::profiling::perf::sampler::MemLock +{ + fn from(value: perf_event_rs::sampling::record::sample::MemLock) -> Self { + match value { + perf_event_rs::sampling::record::sample::MemLock::Na => Self::Na, + perf_event_rs::sampling::record::sample::MemLock::Locked => Self::Locked, + } + } +} + +impl From + for crate::profiling::perf::sampler::MemDtlb +{ + fn from(value: perf_event_rs::sampling::record::sample::MemDtlb) -> Self { + match value { + perf_event_rs::sampling::record::sample::MemDtlb::Na => Self::Na, + perf_event_rs::sampling::record::sample::MemDtlb::Hit => Self::Hit, + perf_event_rs::sampling::record::sample::MemDtlb::Miss => Self::Miss, + perf_event_rs::sampling::record::sample::MemDtlb::L1 => Self::L1, + perf_event_rs::sampling::record::sample::MemDtlb::L2 => Self::L2, + perf_event_rs::sampling::record::sample::MemDtlb::Wk => Self::Wk, + perf_event_rs::sampling::record::sample::MemDtlb::Os => Self::Os, + } + } +} + +impl From + for crate::profiling::perf::sampler::DataSrc +{ + fn from(value: perf_event_rs::sampling::record::sample::DataSrc) -> Self { + Self { + mem_op: value.mem_op.into(), + mem_lvl: value.mem_lvl.into(), + mem_snoop: value.mem_snoop.into(), + mem_lock: value.mem_lock.into(), + mem_dtlb: value.mem_dtlb.into(), + } + } +} + +impl From + for crate::profiling::perf::sampler::SampleBody +{ + fn from(value: perf_event_rs::sampling::record::sample::Body) -> Self { + Self { + sample_id: value.sample_id, + ip: value.ip, + pid: value.pid, + tid: value.tid, + time: value.time, + addr: value.addr, + id: value.id, + stream_id: value.stream_id, + cpu: value.cpu, + period: value.period, + v: value.v.map(Into::into), + ips: value.ips, + data_raw: value.data_raw, + abi_and_regs_user: value.abi_and_regs_user.map(Into::into), + data_stack_user: value.data_stack_user, + weight: value.weight.map(Into::into), + data_src: value.data_src.map(Into::into), + transaction: value.transaction, + abi_and_regs_intr: value.abi_and_regs_intr.map(Into::into), + phys_addr: value.phys_addr, + cgroup: value.cgroup, + data_page_size: value.data_page_size, + code_page_size: value.code_page_size, + } + } +} + +impl From for crate::profiling::perf::sampler::MemberCount { + fn from(value: perf_event_rs::sampling::MemberCount) -> Self { + Self { + event_count: value.event_count, + #[cfg(feature = "linux-6.0")] + event_lost: value.event_lost, + #[cfg(not(feature = "linux-6.0"))] + event_lost: 0, + } + } +} + +impl From + for crate::profiling::perf::sampler::SamplerGroupStat +{ + fn from(value: perf_event_rs::sampling::SamplerGroupStat) -> Self { + Self { + time_enabled: value.time_enabled, + time_running: value.time_running, + member_counts: value + .member_counts + .into_iter() + .map(|(k, v)| (k, v.into())) + .collect(), + } + } +} + +impl From + for crate::profiling::perf::sampler::ReadBody +{ + fn from(value: perf_event_rs::sampling::record::read::Body) -> Self { + Self { + pid: value.pid, + tid: value.tid, + values: value.values.into(), + sample_id: value.sample_id.map(Into::into), + } + } +} + +impl From + for crate::profiling::perf::sampler::ForkBody +{ + fn from(value: perf_event_rs::sampling::record::fork::Body) -> Self { + Self { + pid: value.pid, + ppid: value.ppid, + tid: value.tid, + ptid: value.ptid, + time: value.time, + sample_id: value.sample_id.map(Into::into), + } + } +} + +impl From + for crate::profiling::perf::sampler::ThrottleBody +{ + fn from(value: perf_event_rs::sampling::record::throttle::Body) -> Self { + Self { + time: value.time, + id: value.id, + stream_id: value.stream_id, + sample_id: value.sample_id.map(Into::into), + } + } +} + +impl From + for crate::profiling::perf::sampler::ExitBody +{ + fn from(value: perf_event_rs::sampling::record::exit::Body) -> Self { + Self { + pid: value.pid, + ppid: value.ppid, + tid: value.tid, + ptid: value.ptid, + time: value.time, + sample_id: value.sample_id.map(Into::into), + } + } +} + +impl From + for crate::profiling::perf::sampler::CommBody +{ + fn from(value: perf_event_rs::sampling::record::comm::Body) -> Self { + Self { + pid: value.pid, + tid: value.tid, + comm: value.comm.to_string_lossy().into_owned(), + sample_id: value.sample_id.map(Into::into), + } + } +} + +impl From for crate::profiling::perf::sampler::SampleId { + fn from(value: perf_event_rs::sampling::record::SampleId) -> Self { + Self { + pid: value.pid, + tid: value.tid, + time: value.time, + id1: value.id_1, + stream_id: value.stream_id, + cpu: value.cpu, + id2: value.id_2, + } + } +} + +impl From + for crate::profiling::perf::sampler::LostBody +{ + fn from(value: perf_event_rs::sampling::record::lost::Body) -> Self { + Self { + id: value.id, + lost: value.lost, + sample_id: value.sample_id.map(Into::into), + } + } +} + +impl From + for crate::profiling::perf::sampler::MmapBody +{ + fn from(value: perf_event_rs::sampling::record::mmap::Body) -> Self { + Self { + pid: value.pid, + tid: value.tid, + addr: value.addr, + len: value.len, + pgoff: value.pgoff, + filename: value.filename.to_string_lossy().into_owned(), + } + } +} + +impl From for crate::profiling::perf::sampler::SamplerStat { + fn from(value: perf_event_rs::sampling::SamplerStat) -> Self { + Self { + event_id: value.event_id, + event_count: value.event_count, + #[cfg(feature = "linux-6.0")] + event_lost: value.event_lost, + #[cfg(not(feature = "linux-6.0"))] + event_lost: 0, + time_enabled: value.time_enabled, + time_running: value.time_running, + } + } +} diff --git a/crates/op/host-op-perf/src/lib.rs b/crates/op/host-op-perf/src/lib.rs index 4579861..d31e461 100644 --- a/crates/op/host-op-perf/src/lib.rs +++ b/crates/op/host-op-perf/src/lib.rs @@ -16,7 +16,9 @@ use wasmtime::component::{Linker, ResourceTable}; pub mod convert; pub mod counting; +pub mod sampling; +pub type Sampler = perf_event_rs::sampling::Sampler; pub type Counter = perf_event_rs::counting::Counter; pub type CounterGroup = perf_event_rs::counting::CounterGroup; pub type FixedCounterGroup = perf_event_rs::counting::FixedCounterGroup; @@ -26,6 +28,7 @@ wasmtime::component::bindgen!({ path: "../../../psh-sdk-wit/wit/deps/perf", world: "imports", with: { + "profiling:perf/sampler/sampler" : Sampler, "profiling:perf/counter/counter" : Counter, "profiling:perf/counter-group/counter-group" : CounterGroup, "profiling:perf/counter-group/fixed-counter-group": FixedCounterGroup, @@ -52,6 +55,7 @@ impl PerfCtx { } } +impl profiling::perf::sampler::Host for PerfCtx {} impl profiling::perf::config::Host for PerfCtx {} impl profiling::perf::counter::Host for PerfCtx {} impl profiling::perf::counter_group::Host for PerfCtx {} diff --git a/crates/op/host-op-perf/src/sampling/mod.rs b/crates/op/host-op-perf/src/sampling/mod.rs new file mode 100644 index 0000000..08989bb --- /dev/null +++ b/crates/op/host-op-perf/src/sampling/mod.rs @@ -0,0 +1,94 @@ +use perf_event_rs::{ + config::{Cpu as RawCpu, Process as RawProcess}, + sampling::Sampler, +}; +use wasmtime::component::Resource; + +use crate::{PerfCtx, convert::Wrap, profiling::perf::sampler::*}; + +impl HostSampler for PerfCtx { + fn new( + &mut self, + process: Process, + cpu: Cpu, + cfg: SamplingConfig, + ) -> wasmtime::Result, String>> { + let process = Wrap::::from(&process).into_inner(); + let cpu = Wrap::::from(&cpu).into_inner(); + let sampler = + perf_event_rs::sampling::Sampler::new(&process, &cpu, 512 + 1, &cfg.try_into()?)?; + Ok(self.table.push(sampler).map_err(|v| v.to_string())) + } + + fn enable(&mut self, self_: Resource) -> wasmtime::Result> { + let sampler = self.table.get(&self_)?; + Ok(sampler.enable().map_err(|e| e.to_string())) + } + + fn disable(&mut self, self_: Resource) -> wasmtime::Result> { + let sampler = self.table.get(&self_)?; + Ok(sampler.disable().map_err(|e| e.to_string())) + } + + fn drop(&mut self, rep: Resource) -> wasmtime::Result<()> { + self.table.delete(rep)?; + Ok(()) + } + + fn reset(&mut self, self_: Resource) -> wasmtime::Result> { + let sampler = self.table.get(&self_)?; + Ok(sampler.reset().map_err(|e| e.to_string())) + } + + fn pause(&mut self, self_: Resource) -> wasmtime::Result> { + let sampler = self.table.get(&self_)?; + Ok(sampler.pause().map_err(|e| e.to_string())) + } + + fn resume(&mut self, self_: Resource) -> wasmtime::Result> { + let sampler = self.table.get(&self_)?; + Ok(sampler.resume().map_err(|e| e.to_string())) + } + + fn refresh( + &mut self, + self_: Resource, + refresh: i32, + ) -> wasmtime::Result> { + let sampler = self.table.get(&self_)?; + Ok(sampler.refresh(refresh).map_err(|e| e.to_string())) + } + + fn update_period( + &mut self, + self_: Resource, + new: u64, + ) -> wasmtime::Result> { + let sampler = self.table.get(&self_)?; + Ok(sampler.update_period(new).map_err(|e| e.to_string())) + } + + fn next_record( + &mut self, + self_: Resource, + ) -> wasmtime::Result, String>> { + let sampler = self.table.get_mut(&self_)?; + let map_err = sampler.next_record().map(Into::into); + Ok(Ok(map_err)) + } + + fn event_id(&mut self, self_: Resource) -> wasmtime::Result> { + let sampler = self.table.get_mut(&self_)?; + Ok(sampler.event_id().map_err(|e| e.to_string())) + } + + fn stat(&mut self, self_: Resource) -> wasmtime::Result> { + let sampler = self.table.get_mut(&self_)?; + Ok(sampler.stat().map(Into::into).map_err(|e| e.to_string())) + } + + fn get_raw_fd(&mut self, self_: Resource) -> wasmtime::Result { + let sampler = self.table.get(&self_)?; + Ok(sampler.get_raw_fd()) + } +} diff --git a/psh-sdk-wit b/psh-sdk-wit index 918e4a9..0249565 160000 --- a/psh-sdk-wit +++ b/psh-sdk-wit @@ -1 +1 @@ -Subproject commit 918e4a9c8e7fac01d01dcc8220a66173e20a66c8 +Subproject commit 02495658c1dfa71b38d2d3dfaf523435a4199329