perf_event_data/
config.rs1use std::fmt;
2
3use bitflags::bitflags;
4use perf_event_open_sys::bindings::{self, perf_event_attr, PERF_SAMPLE_BRANCH_HW_INDEX};
5
6use crate::endian::Endian;
7use crate::{ReadFormat, SampleFlags};
8
9bitflags! {
10 #[derive(Copy, Clone, Debug, Default)]
19 struct ConfigFlags : u64 {
20 const READ_FORMAT = ((1u64 << ConfigFlags::READ_FORMAT_WIDTH) - 1);
21 const SAMPLE_TYPE = (u64::MAX << ConfigFlags::READ_FORMAT_WIDTH) & (ConfigFlags::SAMPLE_ID_ALL.bits() - 1);
22
23 const SAMPLE_ID_ALL = 1 << 46;
24 const BRANCH_HW_INDEX = 1 << 47;
25 const MISC = u64::MAX << ConfigFlags::MISC_OFFSET;
26 }
27}
28
29#[allow(dead_code)]
30impl ConfigFlags {
31 const MISC_WIDTH: u32 = u16::BITS;
32 const READ_FORMAT_WIDTH: u32 = (bindings::PERF_FORMAT_MAX - 1).count_ones() + 1;
36 const SAMPLE_TYPE_WIDTH: u32 = (bindings::PERF_SAMPLE_MAX - 1).count_ones();
37
38 const READ_FORMAT_OFFSET: u32 = 0;
39 const SAMPLE_TYPE_OFFSET: u32 = Self::READ_FORMAT_WIDTH;
40 const SAMPLE_ID_ALL_OFFSET: u32 = Self::BRANCH_HW_INDEX_OFFSET - 1;
41 const BRANCH_HW_INDEX_OFFSET: u32 = Self::MISC_OFFSET - 1;
42 const MISC_OFFSET: u32 = u64::BITS - Self::MISC_WIDTH;
43}
44
45impl ConfigFlags {
46 fn new(
47 read_format: ReadFormat,
48 sample_type: SampleFlags,
49 sample_id_all: bool,
50 branch_hw_index: bool,
51 misc: u16,
52 ) -> Self {
53 let mut bits = 0u64;
54 bits |= (sample_id_all as u64) << Self::SAMPLE_ID_ALL_OFFSET;
55 bits |= (branch_hw_index as u64) << Self::BRANCH_HW_INDEX_OFFSET;
56 bits |= (misc as u64) << Self::MISC_OFFSET;
57
58 let mut flags = Self::from_bits_retain(bits);
59 flags.set_read_format(read_format);
60 flags.set_sample_type(sample_type);
61 flags.set_misc(misc);
62
63 flags
64 }
65
66 fn read_format(&self) -> ReadFormat {
67 ReadFormat::from_bits_retain((*self & Self::READ_FORMAT).bits() >> Self::READ_FORMAT_OFFSET)
68 }
69
70 fn sample_type(&self) -> SampleFlags {
71 SampleFlags::from_bits_retain(
72 (*self & Self::SAMPLE_TYPE).bits() >> Self::SAMPLE_TYPE_OFFSET,
73 )
74 }
75
76 fn sample_id_all(&self) -> bool {
77 self.contains(Self::SAMPLE_ID_ALL)
78 }
79
80 fn branch_hw_index(&self) -> bool {
81 self.contains(Self::BRANCH_HW_INDEX)
82 }
83
84 fn misc(&self) -> u16 {
85 ((*self & Self::MISC).bits() >> Self::MISC_OFFSET) as _
86 }
87
88 fn set_misc(&mut self, misc: u16) {
89 *self &= !Self::MISC;
90 *self |= Self::from_bits_retain((misc as u64) << Self::MISC_OFFSET);
91 }
92
93 fn set_sample_type(&mut self, sample_type: SampleFlags) {
94 *self &= !Self::SAMPLE_TYPE;
95 *self |= Self::from_bits_retain(sample_type.bits() << Self::SAMPLE_TYPE_OFFSET)
96 & Self::SAMPLE_TYPE;
97 }
98
99 fn set_read_format(&mut self, read_format: ReadFormat) {
100 *self &= !Self::READ_FORMAT;
101 *self |= Self::from_bits_retain(read_format.bits() << Self::READ_FORMAT_OFFSET)
102 & Self::READ_FORMAT;
103 *self |= Self::from_bits_retain(
104 ((read_format.bits() >> Self::READ_FORMAT_WIDTH != 0) as u64)
105 << (Self::READ_FORMAT_OFFSET + Self::READ_FORMAT_WIDTH - 1),
106 );
107 }
108}
109
110#[derive(Copy, Clone, Debug, Default)]
111#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
112pub(crate) struct RawParseConfig {
113 config_flags: ConfigFlags,
114 sample_regs_user: u64,
115 sample_regs_intr: u64,
116}
117
118#[derive(Clone, Default)]
120pub struct ParseConfig<E> {
121 config: RawParseConfig,
122 endian: E,
123}
124
125impl<E> ParseConfig<E> {
126 pub fn with_endian<E2: Endian>(self, endian: E2) -> ParseConfig<E2> {
128 ParseConfig {
129 endian,
130 config: self.config,
131 }
132 }
133
134 #[allow(dead_code)]
135 pub(crate) fn with_sample_type(mut self, sample_type: SampleFlags) -> Self {
137 self.config.config_flags.set_sample_type(sample_type);
138 self
139 }
140
141 #[allow(dead_code)]
142 pub(crate) fn with_read_format(mut self, read_format: ReadFormat) -> Self {
144 self.config.config_flags.set_read_format(read_format);
145 self
146 }
147
148 pub(crate) fn with_misc(mut self, misc: u16) -> Self {
149 self.config.config_flags.set_misc(misc);
150 self
151 }
152}
153
154impl<E> ParseConfig<E> {
155 pub fn read_format(&self) -> ReadFormat {
158 self.config.config_flags.read_format()
159 }
160
161 pub fn sample_type(&self) -> SampleFlags {
164 self.config.config_flags.sample_type()
165 }
166
167 pub fn regs_user(&self) -> u64 {
170 self.config.sample_regs_user
171 }
172
173 pub fn regs_intr(&self) -> u64 {
180 self.config.sample_regs_intr
181 }
182
183 pub(crate) fn sample_id_all(&self) -> bool {
184 self.config.config_flags.sample_id_all()
185 }
186
187 pub(crate) fn branch_hw_index(&self) -> bool {
188 self.config.config_flags.branch_hw_index()
189 }
190
191 pub(crate) fn misc(&self) -> u16 {
192 self.config.config_flags.misc()
193 }
194
195 pub fn endian(&self) -> &E {
197 &self.endian
198 }
199}
200
201impl From<perf_event_attr> for RawParseConfig {
202 fn from(attrs: perf_event_attr) -> Self {
203 Self {
204 config_flags: ConfigFlags::new(
205 ReadFormat::from_bits_retain(attrs.read_format),
206 SampleFlags::from_bits_retain(attrs.sample_type),
207 attrs.sample_id_all() != 0,
208 (attrs.branch_sample_type & PERF_SAMPLE_BRANCH_HW_INDEX as u64) != 0,
209 0,
210 ),
211 sample_regs_user: attrs.sample_regs_user,
212 sample_regs_intr: attrs.sample_regs_intr,
213 }
214 }
215}
216
217impl<E> From<perf_event_attr> for ParseConfig<E>
218where
219 E: Default,
220{
221 fn from(value: perf_event_attr) -> Self {
222 Self {
223 endian: E::default(),
224 config: RawParseConfig::from(value),
225 }
226 }
227}
228
229impl<E: fmt::Debug> fmt::Debug for ParseConfig<E> {
230 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
231 f.debug_struct("ParseConfig")
232 .field("read_format", &self.read_format())
233 .field("sample_type", &self.sample_type())
234 .field("sample_id_all", &self.sample_id_all())
235 .field("branch_hw_index", &self.branch_hw_index())
236 .field("misc", &format_args!("0x{:X}", self.misc()))
237 .field("regs_user", &format_args!("0x{:X}", self.regs_user()))
238 .field("regs_intr", &format_args!("0x{:X}", self.regs_intr()))
239 .finish()
240 }
241}
242
243#[cfg(feature = "arbitrary")]
244mod fuzzing {
245 use super::*;
246
247 use arbitrary::{Arbitrary, Result, Unstructured};
248
249 impl<'a, E: Endian + Default> arbitrary::Arbitrary<'a> for ParseConfig<E> {
250 fn arbitrary(u: &mut arbitrary::Unstructured) -> arbitrary::Result<Self> {
251 Ok(Self {
252 endian: E::default(),
253 config: RawParseConfig::arbitrary(u)?,
254 })
255 }
256 }
257
258 impl<'a> Arbitrary<'a> for ConfigFlags {
259 fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
260 Ok(Self::from_bits_retain(Arbitrary::arbitrary(u)?))
261 }
262 }
263}
264
265#[test]
266fn assert_sufficient_spare_sample_type_bits() {
267 assert!(ConfigFlags::SAMPLE_TYPE.bits().count_ones() >= ConfigFlags::SAMPLE_TYPE_WIDTH + 8)
268}