linux_perf_data/
features.rs

1use std::fmt;
2
3pub const HEADER_TRACING_DATA: u32 = 1;
4pub const HEADER_BUILD_ID: u32 = 2;
5pub const HEADER_HOSTNAME: u32 = 3;
6pub const HEADER_OSRELEASE: u32 = 4;
7pub const HEADER_VERSION: u32 = 5;
8pub const HEADER_ARCH: u32 = 6;
9pub const HEADER_NRCPUS: u32 = 7;
10pub const HEADER_CPUDESC: u32 = 8;
11pub const HEADER_CPUID: u32 = 9;
12pub const HEADER_TOTAL_MEM: u32 = 10;
13pub const HEADER_CMDLINE: u32 = 11;
14pub const HEADER_EVENT_DESC: u32 = 12;
15pub const HEADER_CPU_TOPOLOGY: u32 = 13;
16pub const HEADER_NUMA_TOPOLOGY: u32 = 14;
17pub const HEADER_BRANCH_STACK: u32 = 15;
18pub const HEADER_PMU_MAPPINGS: u32 = 16;
19pub const HEADER_GROUP_DESC: u32 = 17;
20pub const HEADER_AUXTRACE: u32 = 18;
21pub const HEADER_STAT: u32 = 19;
22pub const HEADER_CACHE: u32 = 20;
23pub const HEADER_SAMPLE_TIME: u32 = 21;
24pub const HEADER_SAMPLE_TOPOLOGY: u32 = 22;
25pub const HEADER_CLOCKID: u32 = 23;
26pub const HEADER_DIR_FORMAT: u32 = 24;
27pub const HEADER_BPF_PROG_INFO: u32 = 25;
28pub const HEADER_BPF_BTF: u32 = 26;
29pub const HEADER_COMPRESSED: u32 = 27;
30pub const HEADER_CPU_PMU_CAPS: u32 = 28;
31pub const HEADER_CLOCK_DATA: u32 = 29;
32pub const HEADER_HYBRID_TOPOLOGY: u32 = 30;
33pub const HEADER_HYBRID_CPU_PMU_CAPS: u32 = 31;
34
35/// simpleperf `FEAT_FILE`
36pub const HEADER_SIMPLEPERF_FILE: u32 = 128;
37/// simpleperf `FEAT_META_INFO`
38pub const HEADER_SIMPLEPERF_META_INFO: u32 = 129;
39/// simpleperf `FEAT_DEBUG_UNWIND`
40pub const HEADER_SIMPLEPERF_DEBUG_UNWIND: u32 = 130;
41/// simpleperf `FEAT_DEBUG_UNWIND_FILE`
42pub const HEADER_SIMPLEPERF_DEBUG_UNWIND_FILE: u32 = 131;
43/// simpleperf `FEAT_FILE2`
44pub const HEADER_SIMPLEPERF_FILE2: u32 = 132;
45
46/// A piece of optional data stored in a perf.data file. Its data is contained in a
47/// "feature section" at the end of the file.
48///
49/// For each used feature, a bit is set in the feature flags in the file header.
50/// The feature sections are stored just after the file's data section; there's
51/// one section for each enabled feature, ordered from low feature bit to high
52/// feature bit.
53#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
54pub struct Feature(pub u32);
55
56impl Feature {
57    pub const TRACING_DATA: Self = Self(HEADER_TRACING_DATA);
58    pub const BUILD_ID: Self = Self(HEADER_BUILD_ID);
59    pub const HOSTNAME: Self = Self(HEADER_HOSTNAME);
60    pub const OSRELEASE: Self = Self(HEADER_OSRELEASE);
61    pub const VERSION: Self = Self(HEADER_VERSION);
62    pub const ARCH: Self = Self(HEADER_ARCH);
63    pub const NRCPUS: Self = Self(HEADER_NRCPUS);
64    pub const CPUDESC: Self = Self(HEADER_CPUDESC);
65    pub const CPUID: Self = Self(HEADER_CPUID);
66    pub const TOTAL_MEM: Self = Self(HEADER_TOTAL_MEM);
67    pub const CMDLINE: Self = Self(HEADER_CMDLINE);
68    pub const EVENT_DESC: Self = Self(HEADER_EVENT_DESC);
69    pub const CPU_TOPOLOGY: Self = Self(HEADER_CPU_TOPOLOGY);
70    pub const NUMA_TOPOLOGY: Self = Self(HEADER_NUMA_TOPOLOGY);
71    pub const BRANCH_STACK: Self = Self(HEADER_BRANCH_STACK);
72    pub const PMU_MAPPINGS: Self = Self(HEADER_PMU_MAPPINGS);
73    pub const GROUP_DESC: Self = Self(HEADER_GROUP_DESC);
74    pub const AUXTRACE: Self = Self(HEADER_AUXTRACE);
75    pub const STAT: Self = Self(HEADER_STAT);
76    pub const CACHE: Self = Self(HEADER_CACHE);
77    pub const SAMPLE_TIME: Self = Self(HEADER_SAMPLE_TIME);
78    pub const SAMPLE_TOPOLOGY: Self = Self(HEADER_SAMPLE_TOPOLOGY);
79    pub const CLOCKID: Self = Self(HEADER_CLOCKID);
80    pub const DIR_FORMAT: Self = Self(HEADER_DIR_FORMAT);
81    pub const BPF_PROG_INFO: Self = Self(HEADER_BPF_PROG_INFO);
82    pub const BPF_BTF: Self = Self(HEADER_BPF_BTF);
83    pub const COMPRESSED: Self = Self(HEADER_COMPRESSED);
84    pub const CPU_PMU_CAPS: Self = Self(HEADER_CPU_PMU_CAPS);
85    pub const CLOCK_DATA: Self = Self(HEADER_CLOCK_DATA);
86    pub const HYBRID_TOPOLOGY: Self = Self(HEADER_HYBRID_TOPOLOGY);
87    pub const HYBRID_CPU_PMU_CAPS: Self = Self(HEADER_HYBRID_CPU_PMU_CAPS);
88    pub const SIMPLEPERF_FILE: Self = Self(HEADER_SIMPLEPERF_FILE);
89    pub const SIMPLEPERF_META_INFO: Self = Self(HEADER_SIMPLEPERF_META_INFO);
90    pub const SIMPLEPERF_DEBUG_UNWIND: Self = Self(HEADER_SIMPLEPERF_DEBUG_UNWIND);
91    pub const SIMPLEPERF_DEBUG_UNWIND_FILE: Self = Self(HEADER_SIMPLEPERF_DEBUG_UNWIND_FILE);
92    pub const SIMPLEPERF_FILE2: Self = Self(HEADER_SIMPLEPERF_FILE2);
93}
94
95impl fmt::Display for Feature {
96    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97        match *self {
98            Self::TRACING_DATA => "TRACING_DATA".fmt(f),
99            Self::BUILD_ID => "BUILD_ID".fmt(f),
100            Self::HOSTNAME => "HOSTNAME".fmt(f),
101            Self::OSRELEASE => "OSRELEASE".fmt(f),
102            Self::VERSION => "VERSION".fmt(f),
103            Self::ARCH => "ARCH".fmt(f),
104            Self::NRCPUS => "NRCPUS".fmt(f),
105            Self::CPUDESC => "CPUDESC".fmt(f),
106            Self::CPUID => "CPUID".fmt(f),
107            Self::TOTAL_MEM => "TOTAL_MEM".fmt(f),
108            Self::CMDLINE => "CMDLINE".fmt(f),
109            Self::EVENT_DESC => "EVENT_DESC".fmt(f),
110            Self::CPU_TOPOLOGY => "CPU_TOPOLOGY".fmt(f),
111            Self::NUMA_TOPOLOGY => "NUMA_TOPOLOGY".fmt(f),
112            Self::BRANCH_STACK => "BRANCH_STACK".fmt(f),
113            Self::PMU_MAPPINGS => "PMU_MAPPINGS".fmt(f),
114            Self::GROUP_DESC => "GROUP_DESC".fmt(f),
115            Self::AUXTRACE => "AUXTRACE".fmt(f),
116            Self::STAT => "STAT".fmt(f),
117            Self::CACHE => "CACHE".fmt(f),
118            Self::SAMPLE_TIME => "SAMPLE_TIME".fmt(f),
119            Self::SAMPLE_TOPOLOGY => "SAMPLE_TOPOLOGY".fmt(f),
120            Self::CLOCKID => "CLOCKID".fmt(f),
121            Self::DIR_FORMAT => "DIR_FORMAT".fmt(f),
122            Self::BPF_PROG_INFO => "BPF_PROG_INFO".fmt(f),
123            Self::BPF_BTF => "BPF_BTF".fmt(f),
124            Self::COMPRESSED => "COMPRESSED".fmt(f),
125            Self::CPU_PMU_CAPS => "CPU_PMU_CAPS".fmt(f),
126            Self::CLOCK_DATA => "CLOCK_DATA".fmt(f),
127            Self::HYBRID_TOPOLOGY => "HYBRID_TOPOLOGY".fmt(f),
128            Self::HYBRID_CPU_PMU_CAPS => "HYBRID_CPU_PMU_CAPS".fmt(f),
129            Self::SIMPLEPERF_FILE => "SIMPLEPERF_FILE".fmt(f),
130            Self::SIMPLEPERF_META_INFO => "SIMPLEPERF_META_INFO".fmt(f),
131            Self::SIMPLEPERF_DEBUG_UNWIND => "SIMPLEPERF_DEBUG_UNWIND".fmt(f),
132            Self::SIMPLEPERF_DEBUG_UNWIND_FILE => "SIMPLEPERF_DEBUG_UNWIND_FILE".fmt(f),
133            Self::SIMPLEPERF_FILE2 => "SIMPLEPERF_FILE2".fmt(f),
134            _ => f.write_fmt(format_args!("Unknown Feature {}", &self.0)),
135        }
136    }
137}
138
139impl fmt::Debug for Feature {
140    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141        write!(f, "{}", self)
142    }
143}
144
145/// The set of features used in the perf file. The perf file contains one
146/// feature section for each feature.
147///
148/// This set is provided in the perf file header.
149/// It has room for 4 * 64 = 256 feature bits.
150#[derive(Clone, Copy, PartialEq, Eq, Hash)]
151pub struct FeatureSet(pub [u64; 4]);
152
153impl FeatureSet {
154    pub const MAX_BITS: u32 = 64 * 4;
155
156    /// The number of features in this set.
157    pub fn len(&self) -> usize {
158        let b = &self.0;
159        let len = b[0].count_ones() + b[1].count_ones() + b[2].count_ones() + b[3].count_ones();
160        len as usize
161    }
162
163    /// Whether the set is empty.
164    pub fn is_empty(&self) -> bool {
165        self.0 == [0, 0, 0, 0]
166    }
167
168    /// Returns an iterator over all features in this set, from low to high.
169    pub fn iter(&self) -> FeatureSetIter {
170        FeatureSetIter {
171            current_feature: Feature(0),
172            set: *self,
173        }
174    }
175
176    /// Checks if the feature is contained in this set.
177    #[inline]
178    pub fn has_feature(&self, feature: Feature) -> bool {
179        if feature.0 >= 256 {
180            return false;
181        }
182        let features_chunk_index = (feature.0 / 64) as usize;
183        let feature_bit = feature.0 % 64;
184        let features_chunk = self.0[features_chunk_index];
185        (features_chunk & (1 << feature_bit)) != 0
186    }
187}
188
189impl fmt::Debug for FeatureSet {
190    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
191        let mut set = f.debug_set();
192        for feature in self.iter() {
193            set.entry(&feature);
194        }
195        set.finish()
196    }
197}
198
199/// An iterator over all the features that are included in a [`FeatureSet`],
200/// ordered from low to high feature bit.
201///
202/// The iteration order is the order in which the feature sections are stored
203/// in a perf.data file.
204pub struct FeatureSetIter {
205    current_feature: Feature,
206    set: FeatureSet,
207}
208
209impl Iterator for FeatureSetIter {
210    type Item = Feature;
211
212    fn next(&mut self) -> Option<Self::Item> {
213        while self.current_feature.0 < FeatureSet::MAX_BITS {
214            let feature = self.current_feature;
215            self.current_feature.0 += 1;
216
217            if self.set.has_feature(feature) {
218                return Some(feature);
219            }
220        }
221        None
222    }
223}