1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
use std::fmt;

pub const HEADER_TRACING_DATA: u32 = 1;
pub const HEADER_BUILD_ID: u32 = 2;
pub const HEADER_HOSTNAME: u32 = 3;
pub const HEADER_OSRELEASE: u32 = 4;
pub const HEADER_VERSION: u32 = 5;
pub const HEADER_ARCH: u32 = 6;
pub const HEADER_NRCPUS: u32 = 7;
pub const HEADER_CPUDESC: u32 = 8;
pub const HEADER_CPUID: u32 = 9;
pub const HEADER_TOTAL_MEM: u32 = 10;
pub const HEADER_CMDLINE: u32 = 11;
pub const HEADER_EVENT_DESC: u32 = 12;
pub const HEADER_CPU_TOPOLOGY: u32 = 13;
pub const HEADER_NUMA_TOPOLOGY: u32 = 14;
pub const HEADER_BRANCH_STACK: u32 = 15;
pub const HEADER_PMU_MAPPINGS: u32 = 16;
pub const HEADER_GROUP_DESC: u32 = 17;
pub const HEADER_AUXTRACE: u32 = 18;
pub const HEADER_STAT: u32 = 19;
pub const HEADER_CACHE: u32 = 20;
pub const HEADER_SAMPLE_TIME: u32 = 21;
pub const HEADER_SAMPLE_TOPOLOGY: u32 = 22;
pub const HEADER_CLOCKID: u32 = 23;
pub const HEADER_DIR_FORMAT: u32 = 24;
pub const HEADER_BPF_PROG_INFO: u32 = 25;
pub const HEADER_BPF_BTF: u32 = 26;
pub const HEADER_COMPRESSED: u32 = 27;
pub const HEADER_CPU_PMU_CAPS: u32 = 28;
pub const HEADER_CLOCK_DATA: u32 = 29;
pub const HEADER_HYBRID_TOPOLOGY: u32 = 30;
pub const HEADER_HYBRID_CPU_PMU_CAPS: u32 = 31;

/// simpleperf `FEAT_META_INFO`
pub const HEADER_SIMPLEPERF_META_INFO: u32 = 128;
/// simpleperf `FEAT_DEBUG_UNWIND`
pub const HEADER_SIMPLEPERF_DEBUG_UNWIND: u32 = 129;
/// simpleperf `FEAT_DEBUG_UNWIND_FILE`
pub const HEADER_SIMPLEPERF_DEBUG_UNWIND_FILE: u32 = 130;
/// simpleperf `FEAT_FILE2`
pub const HEADER_SIMPLEPERF_FILE2: u32 = 131;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FlagFeature {
    TracingData,
    BuildId,
    Hostname,
    OsRelease,
    Version,
    Arch,
    NrCpus,
    CpuDesc,
    CpuId,
    TotalMem,
    Cmdline,
    EventDesc,
    CpuTopology,
    NumaTopology,
    BranchStack,
    PmuMappings,
    GroupDesc,
    Auxtrace,
    Stat,
    Cache,
    SampleTime,
    SampleTopology,
    ClockId,
    DirFormat,
    BpfProgInfo,
    BpfBtf,
    Compressed,
    CpuPmuCaps,
    ClockData,
    HybridTopology,
    HybridCpuPmuCaps,
    SimpleperfMetaInfo,
    SimpleperfDebugUnwind,
    SimpleperfDebugUnwindFile,
    SimpleperfFile2,
}

impl FlagFeature {
    pub fn from_int(i: u32) -> Option<Self> {
        let feature = match i {
            HEADER_TRACING_DATA => Self::TracingData,
            HEADER_BUILD_ID => Self::BuildId,
            HEADER_HOSTNAME => Self::Hostname,
            HEADER_OSRELEASE => Self::OsRelease,
            HEADER_VERSION => Self::Version,
            HEADER_ARCH => Self::Arch,
            HEADER_NRCPUS => Self::NrCpus,
            HEADER_CPUDESC => Self::CpuDesc,
            HEADER_CPUID => Self::CpuId,
            HEADER_TOTAL_MEM => Self::TotalMem,
            HEADER_CMDLINE => Self::Cmdline,
            HEADER_EVENT_DESC => Self::EventDesc,
            HEADER_CPU_TOPOLOGY => Self::CpuTopology,
            HEADER_NUMA_TOPOLOGY => Self::NumaTopology,
            HEADER_BRANCH_STACK => Self::BranchStack,
            HEADER_PMU_MAPPINGS => Self::PmuMappings,
            HEADER_GROUP_DESC => Self::GroupDesc,
            HEADER_AUXTRACE => Self::Auxtrace,
            HEADER_STAT => Self::Stat,
            HEADER_CACHE => Self::Cache,
            HEADER_SAMPLE_TIME => Self::SampleTime,
            HEADER_SAMPLE_TOPOLOGY => Self::SampleTopology,
            HEADER_CLOCKID => Self::ClockId,
            HEADER_DIR_FORMAT => Self::DirFormat,
            HEADER_BPF_PROG_INFO => Self::BpfProgInfo,
            HEADER_BPF_BTF => Self::BpfBtf,
            HEADER_COMPRESSED => Self::Compressed,
            HEADER_CPU_PMU_CAPS => Self::CpuPmuCaps,
            HEADER_CLOCK_DATA => Self::ClockData,
            HEADER_HYBRID_TOPOLOGY => Self::HybridTopology,
            HEADER_HYBRID_CPU_PMU_CAPS => Self::HybridCpuPmuCaps,
            HEADER_SIMPLEPERF_META_INFO => Self::SimpleperfMetaInfo,
            HEADER_SIMPLEPERF_DEBUG_UNWIND => Self::SimpleperfDebugUnwind,
            HEADER_SIMPLEPERF_DEBUG_UNWIND_FILE => Self::SimpleperfDebugUnwindFile,
            HEADER_SIMPLEPERF_FILE2 => Self::SimpleperfFile2,
            _ => return None,
        };
        Some(feature)
    }
}

impl From<FlagFeature> for u32 {
    fn from(flag: FlagFeature) -> Self {
        match flag {
            FlagFeature::TracingData => HEADER_TRACING_DATA,
            FlagFeature::BuildId => HEADER_BUILD_ID,
            FlagFeature::Hostname => HEADER_HOSTNAME,
            FlagFeature::OsRelease => HEADER_OSRELEASE,
            FlagFeature::Version => HEADER_VERSION,
            FlagFeature::Arch => HEADER_ARCH,
            FlagFeature::NrCpus => HEADER_NRCPUS,
            FlagFeature::CpuDesc => HEADER_CPUDESC,
            FlagFeature::CpuId => HEADER_CPUID,
            FlagFeature::TotalMem => HEADER_TOTAL_MEM,
            FlagFeature::Cmdline => HEADER_CMDLINE,
            FlagFeature::EventDesc => HEADER_EVENT_DESC,
            FlagFeature::CpuTopology => HEADER_CPU_TOPOLOGY,
            FlagFeature::NumaTopology => HEADER_NUMA_TOPOLOGY,
            FlagFeature::BranchStack => HEADER_BRANCH_STACK,
            FlagFeature::PmuMappings => HEADER_PMU_MAPPINGS,
            FlagFeature::GroupDesc => HEADER_GROUP_DESC,
            FlagFeature::Auxtrace => HEADER_AUXTRACE,
            FlagFeature::Stat => HEADER_STAT,
            FlagFeature::Cache => HEADER_CACHE,
            FlagFeature::SampleTime => HEADER_SAMPLE_TIME,
            FlagFeature::SampleTopology => HEADER_SAMPLE_TOPOLOGY,
            FlagFeature::ClockId => HEADER_CLOCKID,
            FlagFeature::DirFormat => HEADER_DIR_FORMAT,
            FlagFeature::BpfProgInfo => HEADER_BPF_PROG_INFO,
            FlagFeature::BpfBtf => HEADER_BPF_BTF,
            FlagFeature::Compressed => HEADER_COMPRESSED,
            FlagFeature::CpuPmuCaps => HEADER_CPU_PMU_CAPS,
            FlagFeature::ClockData => HEADER_CLOCK_DATA,
            FlagFeature::HybridTopology => HEADER_HYBRID_TOPOLOGY,
            FlagFeature::HybridCpuPmuCaps => HEADER_HYBRID_CPU_PMU_CAPS,
            FlagFeature::SimpleperfMetaInfo => HEADER_SIMPLEPERF_META_INFO,
            FlagFeature::SimpleperfDebugUnwind => HEADER_SIMPLEPERF_DEBUG_UNWIND,
            FlagFeature::SimpleperfDebugUnwindFile => HEADER_SIMPLEPERF_DEBUG_UNWIND_FILE,
            FlagFeature::SimpleperfFile2 => HEADER_SIMPLEPERF_FILE2,
        }
    }
}

/// The set of feature flags used in the perf file. The perf file contains has one
/// "feature flag section" for each of the flags. This set is provided in the perf
/// file header.
///
/// The set has room for 4 * 64 = 256 header flag bits.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct FlagFeatureSet(pub [u64; 4]);

impl FlagFeatureSet {
    /// The number of flags in this set.
    pub fn len(&self) -> usize {
        let b = &self.0;
        let len = b[0].count_ones() + b[1].count_ones() + b[2].count_ones() + b[3].count_ones();
        len as usize
    }

    /// Whether the set is empty.
    pub fn is_empty(&self) -> bool {
        self.0 == [0, 0, 0, 0]
    }

    /// Emits all feature flags in this set, from low to high.
    pub fn iter(&self) -> FlagFeatureSetIterAll {
        FlagFeatureSetIterAll {
            current_flag: 0,
            set: *self,
        }
    }

    /// Checks if the flag is contained in this set.
    #[inline]
    pub fn has_flag(&self, flag: impl Into<u32>) -> bool {
        let flag: u32 = flag.into();
        if flag >= 256 {
            return false;
        }
        let flags_chunk_index = (flag / 64) as usize;
        let flag_bit = flag % 64;
        let flags_chunk = self.0[flags_chunk_index];
        (flags_chunk & (1 << flag_bit)) != 0
    }
}

impl fmt::Debug for FlagFeatureSet {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut set = f.debug_set();
        for i in self.iter() {
            if let Some(feature) = FlagFeature::from_int(i) {
                set.entry(&feature);
            } else {
                set.entry(&format_args!("Unknown({})", i));
            }
        }
        set.finish()
    }
}

pub struct FlagFeatureSetIterAll {
    current_flag: u32,
    set: FlagFeatureSet,
}

impl Iterator for FlagFeatureSetIterAll {
    type Item = u32;

    fn next(&mut self) -> Option<Self::Item> {
        while self.current_flag < 256 {
            let flag = self.current_flag;
            self.current_flag += 1;

            if self.set.has_flag(flag) {
                return Some(flag);
            }
        }
        None
    }
}