xref: /DragonOS/kernel/src/perf/util.rs (revision fae6e9ade46a52976ad5d099643d51cc20876448)
1*fae6e9adSlinfeng use crate::include::bindings::linux_bpf::{
2*fae6e9adSlinfeng     perf_event_attr, perf_event_header, perf_event_sample_format, perf_sw_ids, perf_type_id,
3*fae6e9adSlinfeng };
4*fae6e9adSlinfeng use crate::syscall::user_access::check_and_clone_cstr;
5*fae6e9adSlinfeng use alloc::string::String;
6*fae6e9adSlinfeng use num_traits::FromPrimitive;
7*fae6e9adSlinfeng use system_error::SystemError;
8*fae6e9adSlinfeng 
9*fae6e9adSlinfeng bitflags! {
10*fae6e9adSlinfeng     pub struct PerfEventOpenFlags: u32 {
11*fae6e9adSlinfeng         const PERF_FLAG_FD_NO_GROUP = 1;
12*fae6e9adSlinfeng         const PERF_FLAG_FD_OUTPUT = 2;
13*fae6e9adSlinfeng         const PERF_FLAG_PID_CGROUP = 4;
14*fae6e9adSlinfeng         const PERF_FLAG_FD_CLOEXEC = 8;
15*fae6e9adSlinfeng     }
16*fae6e9adSlinfeng }
17*fae6e9adSlinfeng 
18*fae6e9adSlinfeng /// The `PerfEventIoc` enum is used to define the ioctl commands for perf events.
19*fae6e9adSlinfeng ///
20*fae6e9adSlinfeng /// See https://elixir.bootlin.com/linux/v6.1/source/include/uapi/linux/perf_event.h#L544
21*fae6e9adSlinfeng #[repr(u32)]
22*fae6e9adSlinfeng #[derive(Debug, Copy, Clone, FromPrimitive)]
23*fae6e9adSlinfeng pub enum PerfEventIoc {
24*fae6e9adSlinfeng     /// Equivalent to [crate::include::bindings::linux_bpf::AYA_PERF_EVENT_IOC_ENABLE].
25*fae6e9adSlinfeng     Enable = 9216,
26*fae6e9adSlinfeng     /// Equivalent to [crate::include::bindings::linux_bpf::AYA_PERF_EVENT_IOC_DISABLE].
27*fae6e9adSlinfeng     Disable = 9217,
28*fae6e9adSlinfeng     /// Equivalent to [crate::include::bindings::linux_bpf::AYA_PERF_EVENT_IOC_SET_BPF].
29*fae6e9adSlinfeng     SetBpf = 1074013192,
30*fae6e9adSlinfeng }
31*fae6e9adSlinfeng 
32*fae6e9adSlinfeng #[derive(Debug, Clone)]
33*fae6e9adSlinfeng #[allow(unused)]
34*fae6e9adSlinfeng /// `perf_event_open` syscall arguments.
35*fae6e9adSlinfeng pub struct PerfProbeArgs {
36*fae6e9adSlinfeng     pub config: perf_sw_ids,
37*fae6e9adSlinfeng     pub name: String,
38*fae6e9adSlinfeng     pub offset: u64,
39*fae6e9adSlinfeng     pub size: u32,
40*fae6e9adSlinfeng     pub type_: perf_type_id,
41*fae6e9adSlinfeng     pub pid: i32,
42*fae6e9adSlinfeng     pub cpu: i32,
43*fae6e9adSlinfeng     pub group_fd: i32,
44*fae6e9adSlinfeng     pub flags: PerfEventOpenFlags,
45*fae6e9adSlinfeng     pub sample_type: Option<perf_event_sample_format>,
46*fae6e9adSlinfeng }
47*fae6e9adSlinfeng 
48*fae6e9adSlinfeng impl PerfProbeArgs {
49*fae6e9adSlinfeng     pub fn try_from(
50*fae6e9adSlinfeng         attr: &perf_event_attr,
51*fae6e9adSlinfeng         pid: i32,
52*fae6e9adSlinfeng         cpu: i32,
53*fae6e9adSlinfeng         group_fd: i32,
54*fae6e9adSlinfeng         flags: u32,
55*fae6e9adSlinfeng     ) -> Result<Self, SystemError> {
56*fae6e9adSlinfeng         let ty = perf_type_id::from_u32(attr.type_).ok_or(SystemError::EINVAL)?;
57*fae6e9adSlinfeng         let config = perf_sw_ids::from_u32(attr.config as u32).ok_or(SystemError::EINVAL)?;
58*fae6e9adSlinfeng         let name = if ty == perf_type_id::PERF_TYPE_MAX {
59*fae6e9adSlinfeng             let name_ptr = unsafe { attr.__bindgen_anon_3.config1 } as *const u8;
60*fae6e9adSlinfeng             let name = check_and_clone_cstr(name_ptr, None)?;
61*fae6e9adSlinfeng             name.into_string().map_err(|_| SystemError::EINVAL)?
62*fae6e9adSlinfeng         } else {
63*fae6e9adSlinfeng             String::new()
64*fae6e9adSlinfeng         };
65*fae6e9adSlinfeng         let sample_ty = perf_event_sample_format::from_u32(attr.sample_type as u32);
66*fae6e9adSlinfeng         let args = PerfProbeArgs {
67*fae6e9adSlinfeng             config,
68*fae6e9adSlinfeng             name,
69*fae6e9adSlinfeng             offset: unsafe { attr.__bindgen_anon_4.config2 },
70*fae6e9adSlinfeng             size: attr.size,
71*fae6e9adSlinfeng             type_: ty,
72*fae6e9adSlinfeng             pid,
73*fae6e9adSlinfeng             cpu,
74*fae6e9adSlinfeng             group_fd,
75*fae6e9adSlinfeng             flags: PerfEventOpenFlags::from_bits_truncate(flags),
76*fae6e9adSlinfeng             sample_type: sample_ty,
77*fae6e9adSlinfeng         };
78*fae6e9adSlinfeng         Ok(args)
79*fae6e9adSlinfeng     }
80*fae6e9adSlinfeng }
81*fae6e9adSlinfeng 
82*fae6e9adSlinfeng /// The event type in our particular use case will be `PERF_RECORD_SAMPLE` or `PERF_RECORD_LOST`.
83*fae6e9adSlinfeng /// `PERF_RECORD_SAMPLE` indicating that there is an actual sample after this header.
84*fae6e9adSlinfeng /// And `PERF_RECORD_LOST` indicating that there is a record lost header following the perf event header.
85*fae6e9adSlinfeng #[repr(C)]
86*fae6e9adSlinfeng #[derive(Debug)]
87*fae6e9adSlinfeng pub struct LostSamples {
88*fae6e9adSlinfeng     pub header: perf_event_header,
89*fae6e9adSlinfeng     pub id: u64,
90*fae6e9adSlinfeng     pub count: u64,
91*fae6e9adSlinfeng }
92*fae6e9adSlinfeng 
93*fae6e9adSlinfeng impl LostSamples {
94*fae6e9adSlinfeng     pub fn as_bytes(&self) -> &[u8] {
95*fae6e9adSlinfeng         unsafe { core::slice::from_raw_parts(self as *const Self as *const u8, size_of::<Self>()) }
96*fae6e9adSlinfeng     }
97*fae6e9adSlinfeng }
98*fae6e9adSlinfeng 
99*fae6e9adSlinfeng #[repr(C)]
100*fae6e9adSlinfeng #[derive(Debug)]
101*fae6e9adSlinfeng pub struct SampleHeader {
102*fae6e9adSlinfeng     pub header: perf_event_header,
103*fae6e9adSlinfeng     pub size: u32,
104*fae6e9adSlinfeng }
105*fae6e9adSlinfeng 
106*fae6e9adSlinfeng impl SampleHeader {
107*fae6e9adSlinfeng     pub fn as_bytes(&self) -> &[u8] {
108*fae6e9adSlinfeng         unsafe { core::slice::from_raw_parts(self as *const Self as *const u8, size_of::<Self>()) }
109*fae6e9adSlinfeng     }
110*fae6e9adSlinfeng }
111*fae6e9adSlinfeng 
112*fae6e9adSlinfeng #[repr(C)]
113*fae6e9adSlinfeng #[derive(Debug)]
114*fae6e9adSlinfeng pub struct PerfSample<'a> {
115*fae6e9adSlinfeng     pub s_hdr: SampleHeader,
116*fae6e9adSlinfeng     pub value: &'a [u8],
117*fae6e9adSlinfeng }
118*fae6e9adSlinfeng 
119*fae6e9adSlinfeng impl<'a> PerfSample<'a> {
120*fae6e9adSlinfeng     pub fn calculate_size(value_size: usize) -> usize {
121*fae6e9adSlinfeng         size_of::<SampleHeader>() + value_size
122*fae6e9adSlinfeng     }
123*fae6e9adSlinfeng }
124