Skip to content

Commit d57fd52

Browse files
Markus Stangeart049
authored andcommitted
chore: Release linux-perf-data version 0.11.1
1 parent b10c53d commit d57fd52

File tree

6 files changed

+613
-53
lines changed

6 files changed

+613
-53
lines changed

README.md

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,16 @@ records" from perf / simpleperf.
1515
This crate also contains parsing code for jitdump files, which are used
1616
in conjunction with perf.data files when profiling JIT runtimes.
1717

18-
# Example
18+
## File Modes
19+
20+
This crate supports two modes for reading perf.data files:
21+
22+
- **File mode** (`parse_file`) - For reading regular perf.data files from disk. Requires `Read + Seek`.
23+
- **Pipe mode** (`parse_pipe`) - For streaming perf.data from pipes, stdin, or network streams. Only requires `Read`.
24+
25+
# Examples
26+
27+
## File Mode Example
1928

2029
```rust
2130
use linux_perf_data::{AttributeDescription, PerfFileReader, PerfFileRecord};
@@ -43,6 +52,40 @@ while let Some(record) = record_iter.next_record(&mut perf_file)? {
4352
}
4453
```
4554

55+
## Pipe Mode Example
56+
57+
Read perf.data from stdin or a pipe (no seeking required):
58+
59+
```rust
60+
use linux_perf_data::{PerfFileReader, PerfFileRecord};
61+
62+
// Read from stdin
63+
let stdin = std::io::stdin();
64+
let PerfFileReader { mut perf_file, mut record_iter } = PerfFileReader::parse_pipe(stdin)?;
65+
66+
println!("Events: {}", perf_file.event_attributes().len());
67+
68+
while let Some(record) = record_iter.next_record(&mut perf_file)? {
69+
match record {
70+
PerfFileRecord::EventRecord { attr_index, record } => {
71+
// Process event records
72+
}
73+
PerfFileRecord::UserRecord(record) => {
74+
// Process user records
75+
}
76+
}
77+
}
78+
```
79+
80+
**Command-line usage:**
81+
```bash
82+
# Stream directly from perf record
83+
perf record -o - sleep 1 | cargo run --example perfpipeinfo
84+
85+
# Or pipe an existing file
86+
cat perf.data | cargo run --example perfpipeinfo
87+
```
88+
4689
## Jitdump example
4790

4891
```rust

examples/perfpipeinfo.rs

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
//! Example: Read and analyze perf.data from stdin in pipe mode
2+
//!
3+
//! This demonstrates the `parse_pipe()` API which works with streams (Read only).
4+
//! Compare with perfdatainfo.rs which uses `parse_file()` (requires Read + Seek).
5+
//!
6+
//! Usage:
7+
//! # Stream directly from perf record:
8+
//! perf record -o - sleep 1 | cargo run --example perfpipeinfo
9+
//!
10+
//! # Or pipe an existing file:
11+
//! cat perf.data | cargo run --example perfpipeinfo
12+
//!
13+
//! # Or from a network stream:
14+
//! nc server 1234 | cargo run --example perfpipeinfo
15+
16+
use std::collections::HashMap;
17+
18+
use linux_perf_data::{PerfFileReader, PerfFileRecord};
19+
#[allow(unused)]
20+
use linux_perf_event_reader::RecordType;
21+
22+
fn main() {
23+
let stdin = std::io::stdin();
24+
let PerfFileReader {
25+
mut perf_file,
26+
mut record_iter,
27+
} = match PerfFileReader::parse_pipe(stdin) {
28+
Ok(reader) => reader,
29+
Err(e) => {
30+
println!("ERROR when creating PerfFileReader: {:?}", e);
31+
return;
32+
}
33+
};
34+
35+
if let Ok(Some(arch)) = perf_file.arch() {
36+
println!("Arch: {arch}");
37+
}
38+
if let Ok(Some(cmdline)) = perf_file.cmdline() {
39+
println!("CmdLine: {cmdline:?}");
40+
}
41+
if let Ok(Some(cpu_desc)) = perf_file.cpu_desc() {
42+
println!("CPU Desc: {cpu_desc}");
43+
}
44+
if let Ok(Some(perf_version)) = perf_file.perf_version() {
45+
println!("Perf version: {perf_version}");
46+
}
47+
if let Ok(Some(frequency)) = perf_file.clock_frequency() {
48+
println!("Clock frequency: {frequency} ns per tick");
49+
}
50+
if let Ok(Some(clock_data)) = perf_file.clock_data() {
51+
println!("Clock data: {clock_data:?}");
52+
}
53+
54+
// Print the feature sections.
55+
let features = perf_file.features();
56+
let features: String = features
57+
.iter()
58+
.map(|f| format!("{f}"))
59+
.collect::<Vec<_>>()
60+
.join(", ");
61+
println!("Features: {features}");
62+
println!();
63+
if let Ok(Some(simpleperf_meta_info)) = perf_file.simpleperf_meta_info() {
64+
println!("Simpleperf meta info:");
65+
for (k, v) in simpleperf_meta_info {
66+
println!(" {k}: {v}");
67+
}
68+
println!();
69+
}
70+
if let Ok(Some(simpleperf_file_symbols)) = perf_file.simpleperf_symbol_tables() {
71+
println!("Simpleperf symbol tables for the following files:");
72+
for f in &simpleperf_file_symbols {
73+
println!(" - {}", f.path);
74+
// println!("{f:#?}");
75+
}
76+
println!();
77+
}
78+
79+
// for event in perf_file.event_attributes() {
80+
// println!("Event: {event:#?}");
81+
// }
82+
83+
let mut event_record_map = HashMap::new();
84+
let mut user_record_map = HashMap::new();
85+
86+
while let Some(record) = record_iter.next_record(&mut perf_file).unwrap() {
87+
match record {
88+
PerfFileRecord::EventRecord { attr_index, record } => {
89+
let record_type = record.record_type;
90+
*event_record_map
91+
.entry(attr_index)
92+
.or_insert_with(HashMap::new)
93+
.entry(record_type)
94+
.or_insert(0) += 1;
95+
match record.parse() {
96+
Ok(parsed_record) => {
97+
// let is_interesting = matches!(record_type, RecordType::FORK | RecordType::COMM | RecordType::MMAP| RecordType::MMAP2);
98+
let is_interesting = false;
99+
if !is_interesting {
100+
continue;
101+
}
102+
103+
if let Some(timestamp) =
104+
record.common_data().ok().and_then(|cd| cd.timestamp)
105+
{
106+
println!(
107+
"{:?} at {} for event {}: {:?}",
108+
record_type, timestamp, attr_index, parsed_record
109+
);
110+
} else {
111+
println!(
112+
"{:?} for event {}: {:?}",
113+
record_type, attr_index, parsed_record
114+
);
115+
}
116+
}
117+
Err(e) => {
118+
println!(
119+
"ERROR when parsing {:?} for event {}: {:?}",
120+
record_type, attr_index, e
121+
);
122+
}
123+
}
124+
}
125+
PerfFileRecord::UserRecord(record) => {
126+
let record_type = record.record_type;
127+
*user_record_map.entry(record_type).or_insert(0) += 1;
128+
match record.parse() {
129+
Ok(_parsed_record) => {
130+
// println!("{:?}: {:?}", record_type, parsed_record);
131+
}
132+
Err(e) => {
133+
println!("ERROR when parsing {:?}: {:?}", record_type, e);
134+
}
135+
}
136+
}
137+
}
138+
}
139+
140+
let mut event_record_map = event_record_map
141+
.into_iter()
142+
.map(|(attr_index, histogram)| {
143+
let sum = histogram.values().sum::<u64>();
144+
(attr_index, histogram, sum)
145+
})
146+
.collect::<Vec<_>>();
147+
event_record_map.sort_by_key(|(_attr_index, _histogram, sum)| -(*sum as i64));
148+
let sum = event_record_map
149+
.iter()
150+
.map(|(_attr_index, _histogram, sum)| sum)
151+
.sum::<u64>();
152+
153+
println!("Event records: {sum} records");
154+
println!();
155+
156+
for (attr_index, record_counts, sum) in event_record_map {
157+
let mut record_counts = record_counts.into_iter().collect::<Vec<_>>();
158+
record_counts.sort_by_key(|(_record_type, count)| -(*count as i64));
159+
println!(
160+
" event {} ({}): {} records",
161+
attr_index,
162+
perf_file.event_attributes()[attr_index]
163+
.name()
164+
.unwrap_or("<no event name found>"),
165+
sum
166+
);
167+
for (record_type, count) in record_counts {
168+
println!(" {:?}: {}", record_type, count);
169+
}
170+
println!();
171+
}
172+
173+
let mut user_record_counts = user_record_map.into_iter().collect::<Vec<_>>();
174+
user_record_counts.sort_by_key(|(_record_type, count)| -(*count as i64));
175+
let sum = user_record_counts
176+
.iter()
177+
.map(|(_record_type, count)| count)
178+
.sum::<u64>();
179+
180+
println!("User records: {sum} records");
181+
println!();
182+
for (record_type, count) in user_record_counts {
183+
println!(" {:?}: {}", record_type, count);
184+
}
185+
}

0 commit comments

Comments
 (0)