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
pub mod codes;
use codes::*;
pub mod record;
use record::{Domain, Event, EventCode, Record, EVENT_EXTRA_MAXLEN};
mod trace;
pub use trace::Trace;
use std::{
collections::HashMap,
fs::File,
io::{Error, ErrorKind, Read, Result},
path::Path,
};
pub fn xentrace_parse(path: &str) -> Result<Trace> {
let mut trace = Trace::default();
{
let path_i = Path::new(path);
let mut file = File::open(path_i)?;
let mut last_tsc = 0u64;
let mut current_cpu = 0u16;
let mut cpus_dom = HashMap::<u16, Domain>::new();
loop {
let record = parse_record(&mut file, &mut last_tsc, &mut current_cpu, &mut cpus_dom);
match record {
Ok(r) => trace.records.push(r),
Err(e) => match e.kind() {
ErrorKind::Other => (),
_ => break,
},
}
}
trace.cpus = cpus_dom.keys().copied().collect()
}
trace.records.sort_unstable();
Ok(trace)
}
#[inline]
fn read_u32(file: &mut File) -> Result<u32> {
let mut buf = [0u8; 4];
file.read_exact(&mut buf)?;
Ok(u32::from_ne_bytes(buf))
}
#[inline(always)]
fn read_u64(file: &mut File) -> Result<u64> {
let mut buf = [0u8; 8];
file.read_exact(&mut buf)?;
Ok(u64::from_ne_bytes(buf))
}
fn parse_event(file: &mut File, last_tsc: &mut u64) -> Result<Event> {
let hdr = read_u32(file)?;
let code = hdr & 0x0FFFFFFF;
let code = EventCode::from_u32(code);
let tsc = {
let in_tsc = (hdr & (1 << 31)) > 0;
if in_tsc {
*last_tsc = read_u64(file)?;
}
*last_tsc
};
let extra = {
let n_extra = ((hdr >> 28) as usize) & EVENT_EXTRA_MAXLEN;
let mut extra = [None; EVENT_EXTRA_MAXLEN];
for i in 0..n_extra {
extra[i] = Some(read_u32(file)?)
}
extra
};
Ok(Event { code, tsc, extra })
}
fn parse_record(
file: &mut File,
last_tsc: &mut u64,
current_cpu: &mut u16,
cpus_dom: &mut HashMap<u16, Domain>,
) -> Result<Record> {
let event = parse_event(file, last_tsc)?;
let code = event.code.into_u32();
if code == TRC_TRACE_CPU_CHANGE {
*current_cpu = event.extra[0].unwrap_or(0) as u16;
return Err(Error::from(ErrorKind::Other));
}
let domain = match code == (code & TRC_SCHED_TO_RUN) {
true => {
let extra_0 = event.extra[0].unwrap_or(0);
let dom = Domain::from_u32(extra_0);
cpus_dom.insert(*current_cpu, dom);
Some(dom)
}
false => cpus_dom.get(current_cpu).copied(),
}
.unwrap_or_default();
Ok(Record {
cpu: *current_cpu,
domain,
event,
})
}