-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathperfpipeinfo.rs
More file actions
185 lines (171 loc) · 6.4 KB
/
perfpipeinfo.rs
File metadata and controls
185 lines (171 loc) · 6.4 KB
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
//! Example: Read and analyze perf.data from stdin in pipe mode
//!
//! This demonstrates the `parse_pipe()` API which works with streams (Read only).
//! Compare with perfdatainfo.rs which uses `parse_file()` (requires Read + Seek).
//!
//! Usage:
//! # Stream directly from perf record:
//! perf record -o - sleep 1 | cargo run --example perfpipeinfo
//!
//! # Or pipe an existing file:
//! cat perf.data | cargo run --example perfpipeinfo
//!
//! # Or from a network stream:
//! nc server 1234 | cargo run --example perfpipeinfo
use std::collections::HashMap;
use linux_perf_data::{PerfFileReader, PerfFileRecord};
#[allow(unused)]
use linux_perf_event_reader::RecordType;
fn main() {
let stdin = std::io::stdin();
let PerfFileReader {
mut perf_file,
mut record_iter,
} = match PerfFileReader::parse_pipe(stdin) {
Ok(reader) => reader,
Err(e) => {
println!("ERROR when creating PerfFileReader: {:?}", e);
return;
}
};
if let Ok(Some(arch)) = perf_file.arch() {
println!("Arch: {arch}");
}
if let Ok(Some(cmdline)) = perf_file.cmdline() {
println!("CmdLine: {cmdline:?}");
}
if let Ok(Some(cpu_desc)) = perf_file.cpu_desc() {
println!("CPU Desc: {cpu_desc}");
}
if let Ok(Some(perf_version)) = perf_file.perf_version() {
println!("Perf version: {perf_version}");
}
if let Ok(Some(frequency)) = perf_file.clock_frequency() {
println!("Clock frequency: {frequency} ns per tick");
}
if let Ok(Some(clock_data)) = perf_file.clock_data() {
println!("Clock data: {clock_data:?}");
}
// Print the feature sections.
let features = perf_file.features();
let features: String = features
.iter()
.map(|f| format!("{f}"))
.collect::<Vec<_>>()
.join(", ");
println!("Features: {features}");
println!();
if let Ok(Some(simpleperf_meta_info)) = perf_file.simpleperf_meta_info() {
println!("Simpleperf meta info:");
for (k, v) in simpleperf_meta_info {
println!(" {k}: {v}");
}
println!();
}
if let Ok(Some(simpleperf_file_symbols)) = perf_file.simpleperf_symbol_tables() {
println!("Simpleperf symbol tables for the following files:");
for f in &simpleperf_file_symbols {
println!(" - {}", f.path);
// println!("{f:#?}");
}
println!();
}
// for event in perf_file.event_attributes() {
// println!("Event: {event:#?}");
// }
let mut event_record_map = HashMap::new();
let mut user_record_map = HashMap::new();
while let Some(record) = record_iter.next_record(&mut perf_file).unwrap() {
match record {
PerfFileRecord::EventRecord { attr_index, record } => {
let record_type = record.record_type;
*event_record_map
.entry(attr_index)
.or_insert_with(HashMap::new)
.entry(record_type)
.or_insert(0) += 1;
match record.parse() {
Ok(parsed_record) => {
// let is_interesting = matches!(record_type, RecordType::FORK | RecordType::COMM | RecordType::MMAP| RecordType::MMAP2);
let is_interesting = false;
if !is_interesting {
continue;
}
if let Some(timestamp) =
record.common_data().ok().and_then(|cd| cd.timestamp)
{
println!(
"{:?} at {} for event {}: {:?}",
record_type, timestamp, attr_index, parsed_record
);
} else {
println!(
"{:?} for event {}: {:?}",
record_type, attr_index, parsed_record
);
}
}
Err(e) => {
println!(
"ERROR when parsing {:?} for event {}: {:?}",
record_type, attr_index, e
);
}
}
}
PerfFileRecord::UserRecord(record) => {
let record_type = record.record_type;
*user_record_map.entry(record_type).or_insert(0) += 1;
match record.parse() {
Ok(_parsed_record) => {
// println!("{:?}: {:?}", record_type, parsed_record);
}
Err(e) => {
println!("ERROR when parsing {:?}: {:?}", record_type, e);
}
}
}
}
}
let mut event_record_map = event_record_map
.into_iter()
.map(|(attr_index, histogram)| {
let sum = histogram.values().sum::<u64>();
(attr_index, histogram, sum)
})
.collect::<Vec<_>>();
event_record_map.sort_by_key(|(_attr_index, _histogram, sum)| -(*sum as i64));
let sum = event_record_map
.iter()
.map(|(_attr_index, _histogram, sum)| sum)
.sum::<u64>();
println!("Event records: {sum} records");
println!();
for (attr_index, record_counts, sum) in event_record_map {
let mut record_counts = record_counts.into_iter().collect::<Vec<_>>();
record_counts.sort_by_key(|(_record_type, count)| -(*count as i64));
println!(
" event {} ({}): {} records",
attr_index,
perf_file.event_attributes()[attr_index]
.name()
.unwrap_or("<no event name found>"),
sum
);
for (record_type, count) in record_counts {
println!(" {:?}: {}", record_type, count);
}
println!();
}
let mut user_record_counts = user_record_map.into_iter().collect::<Vec<_>>();
user_record_counts.sort_by_key(|(_record_type, count)| -(*count as i64));
let sum = user_record_counts
.iter()
.map(|(_record_type, count)| count)
.sum::<u64>();
println!("User records: {sum} records");
println!();
for (record_type, count) in user_record_counts {
println!(" {:?}: {}", record_type, count);
}
}