Skip to content

Commit 47f59fa

Browse files
authored
Merge pull request #74 from andjo403/collapse_threads
stack collaps events from multiple threads correct
2 parents 9d5d1e8 + 255c802 commit 47f59fa

File tree

3 files changed

+81
-37
lines changed

3 files changed

+81
-37
lines changed

flamegraph/src/main.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use std::error::Error;
22
use std::fs::File;
33
use std::io::BufWriter;
44
use std::path::PathBuf;
5-
use std::time::Duration;
65

76
use measureme::ProfilingData;
87

@@ -26,12 +25,7 @@ fn main() -> Result<(), Box<dyn Error>> {
2625

2726
let profiling_data = ProfilingData::new(&opt.file_prefix)?;
2827

29-
let first_event_time = {
30-
let current_time = profiling_data.iter().next().unwrap().timestamp;
31-
current_time + Duration::from_millis(opt.interval)
32-
};
33-
34-
let recorded_stacks = collapse_stacks(profiling_data.iter(), first_event_time, opt.interval)
28+
let recorded_stacks = collapse_stacks(profiling_data.iter(), opt.interval)
3529
.iter()
3630
.map(|(unique_stack, count)| format!("{} {}", unique_stack, count))
3731
.collect::<Vec<_>>();

stack_collapse/src/main.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use std::error::Error;
22
use std::fs::File;
33
use std::io::{BufWriter, Write};
44
use std::path::PathBuf;
5-
use std::time::Duration;
65

76
use measureme::ProfilingData;
87

@@ -24,12 +23,7 @@ fn main() -> Result<(), Box<dyn Error>> {
2423

2524
let profiling_data = ProfilingData::new(&opt.file_prefix)?;
2625

27-
let first_event_time = {
28-
let current_time = profiling_data.iter().next().unwrap().timestamp;
29-
current_time + Duration::from_millis(opt.interval)
30-
};
31-
32-
let recorded_stacks = collapse_stacks(profiling_data.iter(), first_event_time, opt.interval);
26+
let recorded_stacks = collapse_stacks(profiling_data.iter(), opt.interval);
3327

3428
let mut file = BufWriter::new(File::create("out.stacks_folded")?);
3529

tools_lib/src/stack_collapse.rs

Lines changed: 79 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,38 +5,33 @@ use measureme::{Event, TimestampKind};
55

66
pub fn collapse_stacks<'a>(
77
events: impl Iterator<Item = Event<'a>>,
8-
first_event_time: SystemTime,
98
interval: u64,
109
) -> HashMap<String, usize> {
1110
let mut recorded_stacks = HashMap::<String, usize>::new();
12-
13-
let mut next_observation_time = first_event_time;
14-
15-
let mut thread_stacks: HashMap<u64, Vec<Event>> = HashMap::new();
11+
let mut thread_stacks: HashMap<u64, (SystemTime, Vec<Event>)> = HashMap::new();
1612

1713
for event in events {
14+
let (next_observation_time, thread_stack) = thread_stacks
15+
.entry(event.thread_id)
16+
.or_insert((event.timestamp, Vec::new()));
1817
//if this event is after the next_observation_time then we need to record the current stacks
19-
while event.timestamp > next_observation_time {
20-
for (_tid, stack) in &thread_stacks {
21-
let mut stack_string = String::new();
22-
stack_string.push_str("rustc;");
18+
if event.timestamp > *next_observation_time {
19+
let mut stack_string = String::new();
20+
stack_string.push_str("rustc");
2321

24-
for event in stack {
25-
stack_string.push_str(&event.label);
26-
stack_string.push(';');
27-
}
28-
29-
//remove the trailing ';'
30-
stack_string.remove(stack_string.len() - 1);
22+
for event in thread_stack.iter() {
23+
stack_string.push(';');
24+
stack_string.push_str(&event.label);
25+
}
3126

32-
*recorded_stacks.entry(stack_string).or_default() += 1;
27+
let count = recorded_stacks.entry(stack_string).or_default();
3328

34-
next_observation_time += Duration::from_millis(interval);
29+
while event.timestamp > *next_observation_time {
30+
*count += 1;
31+
*next_observation_time += Duration::from_millis(interval);
3532
}
3633
}
3734

38-
let thread_stack = thread_stacks.entry(event.thread_id).or_default();
39-
4035
match event.timestamp_kind {
4136
TimestampKind::Start => {
4237
thread_stack.push(event);
@@ -112,9 +107,7 @@ mod test {
112107
},
113108
];
114109

115-
let first_event_time = events[0].timestamp;
116-
117-
let recorded_stacks = super::collapse_stacks(events.iter().cloned(), first_event_time, 1);
110+
let recorded_stacks = super::collapse_stacks(events.iter().cloned(), 1);
118111

119112
let mut expected_stacks = HashMap::<String, usize>::new();
120113
expected_stacks.insert("rustc;EventB;EventA".into(), 1000);
@@ -124,4 +117,67 @@ mod test {
124117

125118
assert_eq!(expected_stacks, recorded_stacks);
126119
}
120+
121+
#[test]
122+
fn multi_threaded_test() {
123+
let events = [
124+
Event {
125+
event_kind: "Query".into(),
126+
label: "EventA".into(),
127+
additional_data: &[],
128+
timestamp: SystemTime::UNIX_EPOCH + Duration::from_secs(1),
129+
timestamp_kind: TimestampKind::Start,
130+
thread_id: 1,
131+
},
132+
Event {
133+
event_kind: "Query".into(),
134+
label: "EventB".into(),
135+
additional_data: &[],
136+
timestamp: SystemTime::UNIX_EPOCH + Duration::from_secs(3),
137+
timestamp_kind: TimestampKind::Start,
138+
thread_id: 2,
139+
},
140+
Event {
141+
event_kind: "Query".into(),
142+
label: "EventA".into(),
143+
additional_data: &[],
144+
timestamp: SystemTime::UNIX_EPOCH + Duration::from_secs(2),
145+
timestamp_kind: TimestampKind::End,
146+
thread_id: 1,
147+
},
148+
Event {
149+
event_kind: "Query".into(),
150+
label: "EventA".into(),
151+
additional_data: &[],
152+
timestamp: SystemTime::UNIX_EPOCH + Duration::from_secs(4),
153+
timestamp_kind: TimestampKind::Start,
154+
thread_id: 2,
155+
},
156+
Event {
157+
event_kind: "Query".into(),
158+
label: "EventA".into(),
159+
additional_data: &[],
160+
timestamp: SystemTime::UNIX_EPOCH + Duration::from_secs(5),
161+
timestamp_kind: TimestampKind::End,
162+
thread_id: 2,
163+
},
164+
Event {
165+
event_kind: "Query".into(),
166+
label: "EventB".into(),
167+
additional_data: &[],
168+
timestamp: SystemTime::UNIX_EPOCH + Duration::from_secs(6),
169+
timestamp_kind: TimestampKind::End,
170+
thread_id: 2,
171+
},
172+
];
173+
174+
let recorded_stacks = super::collapse_stacks(events.iter().cloned(), 1000);
175+
176+
let mut expected_stacks = HashMap::<String, usize>::new();
177+
expected_stacks.insert("rustc;EventB;EventA".into(), 1);
178+
expected_stacks.insert("rustc;EventB".into(), 2);
179+
expected_stacks.insert("rustc;EventA".into(), 1);
180+
181+
assert_eq!(expected_stacks, recorded_stacks);
182+
}
127183
}

0 commit comments

Comments
 (0)