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; const INHERIT = 1 << 1; const PINNED = 1 << 2; const EXLUSIVE = 1 << 3; const EXCLUDE_USER = 1 << 4; const EXCLUDE_KERNEL = 1 << 5; const EXCLUDE_HV = 1 << 6; const EXCLUDE_IDLE = 1 << 7; const MMAP = 1 << 8; const COMM = 1 << 9; const FREQ = 1 << 10; const INHERIT_STAT = 1 << 11; const ENABLE_ON_EXEC = 1 << 12; const TASK = 1 << 13; const WATERMARK = 1 << 14; const PRECISE_IP1 = 1 << 15;
100 const PRECISE_IP2 = 1 << 16;
101 const MMAP_DATA = 1 << 17; const SAMPLE_ID_ALL = 1 << 18; const EXCLUDE_HOST = 1 << 19; const EXCLUDE_GUEST = 1 << 20; const EXCLUDE_CALLCHAIN_KERNEL = 1 << 21; const EXCLUDE_CALLCHAIN_USER = 1 << 22; const MMAP2 = 1 << 23; const COMM_EXEC = 1 << 24; const USE_CLOCKID = 1 << 25; const CONTEXT_SWITCH = 1 << 26; const WRITE_BACKWARD = 1 << 27; }
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, 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, pub bp_type: u32,
160 pub bp_addr_or_config1: u32,
161 pub bp_len_or_config2: u64,
162 pub branch_sample_type: u64, pub sample_regs_user: u64, pub sample_stack_user: u32, pub clockid: i32,
166 pub sample_regs_intr: u64,
173 pub aux_watermark: u32, 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 }
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 call_chain: Vec<u64>, },
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}