linux_perf_file_reader/
lib.rs

1#![recursion_limit = "1024"]
2#[macro_use]
3extern crate error_chain;
4#[macro_use]
5extern crate log;
6#[macro_use]
7extern crate bitflags;
8#[macro_use]
9extern crate serde_derive;
10extern crate serde;
11
12use std::fs::File;
13use std::io::Seek;
14use std::{io, mem};
15
16mod event_reader;
17mod header;
18mod info_reader;
19use header::*;
20mod tools;
21use tools::read_raw;
22
23mod errors {
24    error_chain! {
25        foreign_links {
26            IOError(::std::io::Error);
27        }
28
29        errors {
30            InvalidSinature {
31                description("invalid perf file signature")
32            }
33            NoEventInInfoSection {
34                description("cannot read dump without event info")
35            }
36            NoIndentifierInEventInInfoAttributes {
37                description("cannot read dump without IDENTIFIER flag and different sample format")
38            }
39        }
40    }
41}
42
43use errors::*;
44
45pub use errors::Error;
46pub use errors::ErrorKind;
47
48#[repr(u32)]
49#[derive(Debug)]
50pub enum PerfType {
51    Hardware = 0,
52    Software = 1,
53    Tracepoint = 2,
54    HwCache = 3,
55    Raw = 4,
56    Breakpoint = 5,
57}
58
59#[repr(u64)]
60#[derive(Debug)]
61pub enum HwId {
62    CpuCycles = 0,
63    Instructions = 1,
64    CacheReferences = 2,
65    CacheMisses = 3,
66    BranchInstructions = 4,
67    BranchMisses = 5,
68    BusCycles = 6,
69    StalledCyclesFrontend = 7,
70    StalledCyclesBackend = 8,
71    RefCpuCycles = 9,
72}
73
74bitflags! {
75    pub struct AttrFlags: u64 {
76        const DISABLED          = 1; /* off by default        */
77        const INHERIT           = 1 << 1; /* children inherit it   */
78        const PINNED            = 1 << 2; /* must always be on PMU */
79        const EXLUSIVE          = 1 << 3; /* only group on PMU     */
80        const EXCLUDE_USER      = 1 << 4; /* don't count user      */
81        const EXCLUDE_KERNEL    = 1 << 5; /* ditto kernel          */
82        const EXCLUDE_HV        = 1 << 6; /* ditto hypervisor      */
83        const EXCLUDE_IDLE      = 1 << 7; /* don't count when idle */
84        const MMAP              = 1 << 8; /* include mmap data     */
85        const COMM              = 1 << 9; /* include comm data     */
86        const FREQ              = 1 << 10; /* use freq, not period  */
87        const INHERIT_STAT      = 1 << 11; /* per task counts       */
88        const ENABLE_ON_EXEC    = 1 << 12; /* next exec enables     */
89        const TASK              = 1 << 13; /* trace fork/exit       */
90        const WATERMARK         = 1 << 14; /* wakeup_watermark      */
91        /*
92         * precise_ip:
93         *
94         *  0 - SAMPLE_IP can have arbitrary skid
95         *  1 - SAMPLE_IP must have constant skid
96         *  2 - SAMPLE_IP requested to have 0 skid
97         *  3 - SAMPLE_IP must have 0 skid
98         */
99        const PRECISE_IP1      = 1 << 15;
100        const PRECISE_IP2      = 1 << 16;
101        const MMAP_DATA         = 1 << 17; /* non-exec mmap data    */
102        const SAMPLE_ID_ALL     = 1 << 18; /* sample_type all events */
103        const EXCLUDE_HOST      = 1 << 19; /* don't count in host   */
104        const EXCLUDE_GUEST     = 1 << 20; /* don't count in guest  */
105        const EXCLUDE_CALLCHAIN_KERNEL  = 1 << 21; /* exclude kernel callchains */
106        const EXCLUDE_CALLCHAIN_USER  = 1 << 22; /* exclude user callchains */
107        const MMAP2             = 1 << 23; /* include mmap with inode data     */
108        const COMM_EXEC         = 1 << 24; /* flag comm events that are due to an exec */
109        const USE_CLOCKID       = 1 << 25; /* use @clockid for time fields */
110        const CONTEXT_SWITCH    = 1 << 26; /* context switch data */
111        const WRITE_BACKWARD    = 1 << 27; /* Write ring buffer from end to beginning */
112    }
113}
114
115bitflags! {
116    pub struct SampleFormat: u64 {
117        const IP	    	= 1 << 0;
118        const TID			= 1 << 1;
119        const TIME			= 1 << 2;
120        const ADDR			= 1 << 3;
121        const READ			= 1 << 4;
122        const CALLCHAIN	    = 1 << 5;
123        const ID			= 1 << 6;
124        const CPU			= 1 << 7;
125        const PERIOD		= 1 << 8;
126        const STREAM_ID		= 1 << 9;
127        const RAW			= 1 << 10;
128        const BRANCH_STACK	= 1 << 11;
129        const REGS_USER		= 1 << 12;
130        const STACK_USER	= 1 << 13;
131        const WEIGHT		= 1 << 14;
132        const DATA_SRC		= 1 << 15;
133        const IDENTIFIER	= 1 << 16;
134        const TRANSACTION	= 1 << 17;
135        const REGS_INTR		= 1 << 18;
136    }
137}
138
139bitflags! {
140    pub struct ReadFormat: u64 {
141        const TOTAL_TIME_ENABLED    = 1 << 0;
142        const TOTAL_TIME_RUNNING	= 1 << 1;
143        const ID				    = 1 << 2;
144        const GROUP			        = 1 << 3;
145    }
146}
147
148#[repr(C)]
149#[derive(Debug)]
150pub struct EventAttributes {
151    pub perf_type: PerfType,
152    pub size: u32,
153    pub config: u64, //TODO: HwId for type hardware,
154    pub sample_period_or_freq: u64,
155    pub sample_format: SampleFormat,
156    pub read_format: ReadFormat,
157    pub flags: AttrFlags,
158    pub wakeup_events_or_watermakr: u32, /* wakeup every n events or bytes before wakeup   */
159    pub bp_type: u32,
160    pub bp_addr_or_config1: u32,
161    pub bp_len_or_config2: u64,
162    pub branch_sample_type: u64, // enum perf_branch_sample_type
163    pub sample_regs_user: u64,   // Defines set of user regs to dump on samples See asm/perf_regs.h.
164    pub sample_stack_user: u32,  // Defines size of the user stack to dump on samples.
165    pub clockid: i32,
166    /*
167     * Defines set of regs to dump for each sample
168     * state captured on:
169     *  - precise = 0: PMU interrupt
170     *  - precise > 0: sampled instruction
171     */
172    pub sample_regs_intr: u64,
173    pub aux_watermark: u32, //Wakeup watermark for AUX area
174    pub sample_max_stack: u16,
175    pub reserved_2: u16,
176}
177
178#[derive(Debug)]
179pub struct Perf {
180    pub info: Info,
181    pub event_attributes: Vec<EventAttributes>,
182    pub events: Vec<Event>,
183    pub start: u64,
184    pub end: u64,
185}
186
187#[derive(Debug, Serialize)]
188pub struct Info {
189    pub hostname: Option<String>,
190    pub os_release: Option<String>,
191    pub tools_version: Option<String>,
192    pub arch: Option<String>,
193    pub cpu_count: Option<CpuCount>,
194    pub cpu_description: Option<String>,
195    pub cpu_id: Option<String>,
196    pub total_memory: Option<u64>,
197    pub command_line: Option<Vec<String>>,
198    pub cpu_topology: Option<Vec<String>>,
199    pub event_descriptions: Option<Vec<EventDescription>>,
200    // TODO add others
201}
202
203#[repr(C)]
204#[derive(Debug, Serialize)]
205pub struct CpuCount {
206    pub online: u32,
207    pub available: u32,
208}
209
210#[derive(Debug, Serialize)]
211pub struct EventDescription {
212    #[serde(skip_serializing)]
213    pub attributes: EventAttributes,
214    pub name: String,
215    pub ids: Vec<u64>,
216}
217
218#[derive(Debug)]
219pub enum Event {
220    MMap {
221        pid: u32,
222        tid: u32,
223        addr: u64,
224        len: u64,
225        pgoff: u64,
226        filename: String,
227        sample_id: SampleId,
228    },
229    MMap2 {
230        pid: u32,
231        tid: u32,
232        addr: u64,
233        len: u64,
234        pgoff: u64,
235        maj: u32,
236        min: u32,
237        ino: u64,
238        ino_generation: u64,
239        prot: u32,
240        flags: u32,
241        filename: String,
242        sample_id: SampleId,
243    },
244    Sample {
245        identifier: Option<u64>,
246        ip: Option<u64>,
247        pid: Option<u32>,
248        tid: Option<u32>,
249        time: Option<u64>,
250        addr: Option<u64>,
251        id: Option<u64>,
252        stream_id: Option<u64>,
253        cpu: Option<u32>,
254        res: Option<u32>,
255        period: Option<u64>,
256        //TODO read_format
257        call_chain: Vec<u64>, // TODO add others
258    },
259    Exit {
260        pid: u32,
261        ppid: u32,
262        tid: u32,
263        ptid: u32,
264        time: u64,
265        sample_id: SampleId,
266    },
267    Comm {
268        pid: u32,
269        tid: u32,
270        comm: String,
271        sample_id: SampleId,
272    },
273    FinishedRound,
274    Unsupported,
275}
276
277#[repr(C)]
278#[derive(Debug)]
279pub struct SampleId {
280    pub pid: Option<u32>,
281    pub tid: Option<u32>,
282    pub time: Option<u64>,
283    pub id: Option<u64>,
284    pub stream_id: Option<u64>,
285    pub cpu: Option<u32>,
286    pub res: Option<u32>,
287    pub identifier: Option<u64>,
288}
289
290pub fn is_perf_file<P: std::convert::AsRef<std::path::Path>>(path: &P) -> Result<bool> {
291    let metadata = std::fs::metadata(path)?;
292    if metadata.len() < mem::size_of::<PerfHeader>() as u64 {
293        return Ok(false);
294    }
295    let mut file = File::open(&path)?;
296    let header: PerfHeader = read_raw(&mut file)?;
297    Ok(header.magic == PERF_FILE_SIGNATURE)
298}
299
300pub fn read_perf_file_info<P: std::convert::AsRef<std::path::Path>>(path: &P) -> Result<Info> {
301    let mut file = File::open(path)?;
302    let header: PerfHeader = read_raw(&mut file)?;
303    if header.magic != PERF_FILE_SIGNATURE {
304        return Err(ErrorKind::InvalidSinature.into());
305    }
306    Ok(info_reader::read_info(&mut file, &header)?)
307}
308
309pub fn read_perf_file<P: std::convert::AsRef<std::path::Path>>(path: &P) -> Result<Perf> {
310    let mut file = File::open(path)?;
311    debug!("read header");
312    let header: PerfHeader = read_raw(&mut file)?;
313    if header.magic != PERF_FILE_SIGNATURE {
314        return Err(ErrorKind::InvalidSinature.into());
315    }
316    debug!("header: {:?}\nread info", header);
317    let info = info_reader::read_info(&mut file, &header)?;
318
319    debug!("read attr");
320    let event_attributes = (0..(header.attrs.size / header.attr_size))
321        .map(|i| {
322            file.seek(io::SeekFrom::Start(
323                header.attrs.offset + i * header.attr_size,
324            ))?;
325            Ok(read_raw(&mut file)?)
326        })
327        .collect::<Result<Vec<_>>>()?;
328
329    if info.event_descriptions.is_none() {
330        Err(ErrorKind::NoEventInInfoSection.into())
331    } else {
332        let (events, start, end) = event_reader::read_events(
333            &mut file,
334            &header,
335            &info.event_descriptions.as_ref().unwrap(),
336        )?;
337        Ok(Perf {
338            info,
339            event_attributes,
340            events,
341            start,
342            end,
343        })
344    }
345}