linux_perf_event_reader/
parse_info.rs

1use crate::{AttrFlags, BranchSampleFormat, Endianness, PerfEventAttr, ReadFormat, SampleFormat};
2
3#[derive(Clone, Copy, Debug, PartialEq, Eq)]
4pub struct RecordParseInfo {
5    pub endian: Endianness,
6    pub sample_format: SampleFormat,
7    pub branch_sample_format: BranchSampleFormat,
8    pub read_format: ReadFormat,
9    pub common_data_offset_from_end: Option<u8>, // 0..=48
10    pub sample_regs_user: u64,
11    pub user_regs_count: u8, // 0..=64
12    pub sample_regs_intr: u64,
13    pub intr_regs_count: u8, // 0..=64
14    pub id_parse_info: RecordIdParseInfo,
15    pub nonsample_record_time_offset_from_end: Option<u8>, // 0..=40
16    pub sample_record_time_offset_from_start: Option<u8>,  // 0..=32
17}
18
19#[derive(Clone, Copy, Debug, PartialEq, Eq)]
20pub struct RecordIdParseInfo {
21    pub nonsample_record_id_offset_from_end: Option<u8>, // 0..=32
22    pub sample_record_id_offset_from_start: Option<u8>,  // 0..=24
23}
24
25impl RecordParseInfo {
26    pub fn new(attr: &PerfEventAttr, endian: Endianness) -> Self {
27        let sample_format = attr.sample_format;
28        let branch_sample_format = attr.branch_sample_format;
29        let read_format = attr.read_format;
30
31        // struct sample_id {
32        //     { u32 pid, tid; }   /* if PERF_SAMPLE_TID set */
33        //     { u64 time;     }   /* if PERF_SAMPLE_TIME set */
34        //     { u64 id;       }   /* if PERF_SAMPLE_ID set */
35        //     { u64 stream_id;}   /* if PERF_SAMPLE_STREAM_ID set  */
36        //     { u32 cpu, res; }   /* if PERF_SAMPLE_CPU set */
37        //     { u64 id;       }   /* if PERF_SAMPLE_IDENTIFIER set */
38        // };
39        let common_data_offset_from_end = if attr.flags.contains(AttrFlags::SAMPLE_ID_ALL) {
40            Some(
41                sample_format
42                    .intersection(
43                        SampleFormat::TID
44                            | SampleFormat::TIME
45                            | SampleFormat::ID
46                            | SampleFormat::STREAM_ID
47                            | SampleFormat::CPU
48                            | SampleFormat::IDENTIFIER,
49                    )
50                    .bits()
51                    .count_ones() as u8
52                    * 8,
53            )
54        } else {
55            None
56        };
57        let sample_regs_user = attr.sample_regs_user;
58        let user_regs_count = sample_regs_user.count_ones() as u8;
59        let sample_regs_intr = attr.sample_regs_intr;
60        let intr_regs_count = sample_regs_intr.count_ones() as u8;
61        let nonsample_record_time_offset_from_end = if attr.flags.contains(AttrFlags::SAMPLE_ID_ALL)
62            && sample_format.contains(SampleFormat::TIME)
63        {
64            Some(
65                sample_format
66                    .intersection(
67                        SampleFormat::TIME
68                            | SampleFormat::ID
69                            | SampleFormat::STREAM_ID
70                            | SampleFormat::CPU
71                            | SampleFormat::IDENTIFIER,
72                    )
73                    .bits()
74                    .count_ones() as u8
75                    * 8,
76            )
77        } else {
78            None
79        };
80
81        // { u64 id;           } && PERF_SAMPLE_IDENTIFIER
82        // { u64 ip;           } && PERF_SAMPLE_IP
83        // { u32 pid; u32 tid; } && PERF_SAMPLE_TID
84        // { u64 time;         } && PERF_SAMPLE_TIME
85        // { u64 addr;         } && PERF_SAMPLE_ADDR
86        // { u64 id;           } && PERF_SAMPLE_ID
87        let sample_record_time_offset_from_start = if sample_format.contains(SampleFormat::TIME) {
88            Some(
89                sample_format
90                    .intersection(SampleFormat::IDENTIFIER | SampleFormat::IP | SampleFormat::TID)
91                    .bits()
92                    .count_ones() as u8
93                    * 8,
94            )
95        } else {
96            None
97        };
98
99        Self {
100            endian,
101            sample_format,
102            branch_sample_format,
103            read_format,
104            common_data_offset_from_end,
105            sample_regs_user,
106            user_regs_count,
107            sample_regs_intr,
108            intr_regs_count,
109            nonsample_record_time_offset_from_end,
110            sample_record_time_offset_from_start,
111            id_parse_info: RecordIdParseInfo::new(attr),
112        }
113    }
114}
115
116impl RecordIdParseInfo {
117    pub fn new(attr: &PerfEventAttr) -> Self {
118        let sample_format = attr.sample_format;
119        let nonsample_record_id_offset_from_end = if attr.flags.contains(AttrFlags::SAMPLE_ID_ALL)
120            && sample_format.intersects(SampleFormat::ID | SampleFormat::IDENTIFIER)
121        {
122            if sample_format.contains(SampleFormat::IDENTIFIER) {
123                Some(8)
124            } else {
125                Some(
126                    sample_format
127                        .intersection(
128                            SampleFormat::ID
129                                | SampleFormat::STREAM_ID
130                                | SampleFormat::CPU
131                                | SampleFormat::IDENTIFIER,
132                        )
133                        .bits()
134                        .count_ones() as u8
135                        * 8,
136                )
137            }
138        } else {
139            None
140        };
141
142        // { u64 id;           } && PERF_SAMPLE_IDENTIFIER
143        // { u64 ip;           } && PERF_SAMPLE_IP
144        // { u32 pid; u32 tid; } && PERF_SAMPLE_TID
145        // { u64 time;         } && PERF_SAMPLE_TIME
146        // { u64 addr;         } && PERF_SAMPLE_ADDR
147        // { u64 id;           } && PERF_SAMPLE_ID
148        let sample_record_id_offset_from_start = if sample_format.contains(SampleFormat::IDENTIFIER)
149        {
150            Some(0)
151        } else if sample_format.contains(SampleFormat::ID) {
152            Some(
153                sample_format
154                    .intersection(
155                        SampleFormat::IP
156                            | SampleFormat::TID
157                            | SampleFormat::TIME
158                            | SampleFormat::ADDR,
159                    )
160                    .bits()
161                    .count_ones() as u8
162                    * 8,
163            )
164        } else {
165            None
166        };
167
168        Self {
169            nonsample_record_id_offset_from_end,
170            sample_record_id_offset_from_start,
171        }
172    }
173}