Skip to content

Commit 7199065

Browse files
Improve SerializationSink benchmarks and tests.
1 parent f3c7f67 commit 7199065

File tree

4 files changed

+117
-43
lines changed

4 files changed

+117
-43
lines changed

analyzeme/benches/serialization_bench.rs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,35 @@ use measureme::{FileSerializationSink, MmapSerializationSink};
88
#[bench]
99
fn bench_file_serialization_sink(bencher: &mut test::Bencher) {
1010
bencher.iter(|| {
11-
testing_common::run_end_to_end_serialization_test::<FileSerializationSink>(
12-
"file_serialization_sink_test",
11+
testing_common::run_serialization_bench::<FileSerializationSink>(
12+
"file_serialization_sink_test", 500_000, 1
1313
);
1414
});
1515
}
1616

1717
#[bench]
1818
fn bench_mmap_serialization_sink(bencher: &mut test::Bencher) {
1919
bencher.iter(|| {
20-
testing_common::run_end_to_end_serialization_test::<MmapSerializationSink>(
21-
"mmap_serialization_sink_test",
20+
testing_common::run_serialization_bench::<MmapSerializationSink>(
21+
"mmap_serialization_sink_test", 500_000, 1
22+
);
23+
});
24+
}
25+
26+
#[bench]
27+
fn bench_file_serialization_sink_8_threads(bencher: &mut test::Bencher) {
28+
bencher.iter(|| {
29+
testing_common::run_serialization_bench::<FileSerializationSink>(
30+
"file_serialization_sink_test", 50_000, 8
31+
);
32+
});
33+
}
34+
35+
#[bench]
36+
fn bench_mmap_serialization_sink_8_threads(bencher: &mut test::Bencher) {
37+
bencher.iter(|| {
38+
testing_common::run_serialization_bench::<MmapSerializationSink>(
39+
"mmap_serialization_sink_test", 50_000, 8
2240
);
2341
});
2442
}

analyzeme/src/testing_common.rs

Lines changed: 80 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::timestamp::Timestamp;
2-
use crate::{Event, LightweightEvent, ProfilingData};
2+
use crate::{Event, ProfilingData};
33
use measureme::{Profiler, SerializationSink, StringId};
44
use rustc_hash::FxHashMap;
55
use std::borrow::Cow;
@@ -19,12 +19,16 @@ fn mk_filestem(file_name_stem: &str) -> PathBuf {
1919
}
2020

2121
// Generate some profiling data. This is the part that would run in rustc.
22-
fn generate_profiling_data<S: SerializationSink>(filestem: &Path) -> Vec<Event<'static>> {
22+
fn generate_profiling_data<S: SerializationSink>(
23+
filestem: &Path,
24+
num_stacks: usize,
25+
num_threads: usize,
26+
) -> Vec<Event<'static>> {
2327
let profiler = Arc::new(Profiler::<S>::new(Path::new(filestem)).unwrap());
2428

2529
let event_id_reserved = StringId::reserved(42);
2630

27-
let event_ids = &[
31+
let event_ids = vec![
2832
(
2933
profiler.alloc_string("Generic"),
3034
profiler.alloc_string("SomeGenericActivity"),
@@ -39,20 +43,33 @@ fn generate_profiling_data<S: SerializationSink>(filestem: &Path) -> Vec<Event<'
3943
event_ids_as_str.insert(event_ids[1].0, "Query");
4044
event_ids_as_str.insert(event_ids[1].1, "SomeQuery");
4145

42-
let mut expected_events = Vec::new();
46+
let threads: Vec<_> = (0.. num_threads).map(|thread_id| {
47+
let event_ids = event_ids.clone();
48+
let profiler = profiler.clone();
49+
let event_ids_as_str = event_ids_as_str.clone();
4350

44-
for i in 0..10_000 {
45-
// Allocate some invocation stacks
51+
std::thread::spawn(move || {
52+
let mut expected_events = Vec::new();
4653

47-
pseudo_invocation(
48-
&profiler,
49-
i,
50-
4,
51-
event_ids,
52-
&event_ids_as_str,
53-
&mut expected_events,
54-
);
55-
}
54+
for i in 0..num_stacks {
55+
// Allocate some invocation stacks
56+
57+
pseudo_invocation(
58+
&profiler,
59+
i,
60+
thread_id as u32,
61+
4,
62+
&event_ids[..],
63+
&event_ids_as_str,
64+
&mut expected_events,
65+
);
66+
}
67+
68+
expected_events
69+
})
70+
}).collect();
71+
72+
let expected_events: Vec<_> = threads.into_iter().flat_map(|t| t.join().unwrap()).collect();
5673

5774
// An example of allocating the string contents of an event id that has
5875
// already been used
@@ -67,53 +84,83 @@ fn process_profiling_data(filestem: &Path, expected_events: &[Event<'static>]) {
6784
let profiling_data = ProfilingData::new(filestem).unwrap();
6885

6986
check_profiling_data(
70-
&mut profiling_data.iter(),
87+
&mut profiling_data.iter().map(|e| e.to_event()),
7188
&mut expected_events.iter().cloned(),
7289
expected_events.len(),
7390
);
7491
check_profiling_data(
75-
&mut profiling_data.iter().rev(),
92+
&mut profiling_data.iter().rev().map(|e| e.to_event()),
7693
&mut expected_events.iter().rev().cloned(),
7794
expected_events.len(),
7895
);
7996
}
8097

8198
fn check_profiling_data(
82-
actual_lightweight_events: &mut dyn Iterator<Item = LightweightEvent<'_>>,
99+
actual_events: &mut dyn Iterator<Item = Event<'_>>,
83100
expected_events: &mut dyn Iterator<Item = Event<'_>>,
84101
num_expected_events: usize,
85102
) {
86103
let mut count = 0;
87104

105+
// This assertion makes sure that the ExactSizeIterator impl works as expected.
88106
assert_eq!(
89107
(num_expected_events, Some(num_expected_events)),
90-
actual_lightweight_events.size_hint()
108+
actual_events.size_hint()
91109
);
92110

93-
for (actual_lightweight_event, expected_event) in actual_lightweight_events.zip(expected_events) {
94-
let actual_event = actual_lightweight_event.to_event();
95-
assert_eq!(actual_event.event_kind, expected_event.event_kind);
96-
assert_eq!(actual_event.label, expected_event.label);
97-
assert_eq!(actual_event.additional_data, expected_event.additional_data);
98-
assert_eq!(
99-
actual_event.timestamp.is_instant(),
100-
expected_event.timestamp.is_instant()
101-
);
102-
103-
count += 1;
111+
let actual_events_per_thread = collect_events_per_thread(actual_events);
112+
let expected_events_per_thread = collect_events_per_thread(expected_events);
113+
114+
let thread_ids: Vec<_> = actual_events_per_thread.keys().collect();
115+
assert_eq!(thread_ids, expected_events_per_thread.keys().collect::<Vec<_>>());
116+
117+
for thread_id in thread_ids {
118+
let actual_events = &actual_events_per_thread[thread_id];
119+
let expected_events = &expected_events_per_thread[thread_id];
120+
121+
assert_eq!(actual_events.len(), expected_events.len());
122+
123+
for (actual_event, expected_event) in actual_events.iter().zip(expected_events.iter()) {
124+
assert_eq!(actual_event.event_kind, expected_event.event_kind);
125+
assert_eq!(actual_event.label, expected_event.label);
126+
assert_eq!(actual_event.additional_data, expected_event.additional_data);
127+
assert_eq!(
128+
actual_event.timestamp.is_instant(),
129+
expected_event.timestamp.is_instant()
130+
);
131+
132+
count += 1;
133+
}
104134
}
135+
105136
assert_eq!(count, num_expected_events);
106137
}
107138

108-
pub fn run_end_to_end_serialization_test<S: SerializationSink>(file_name_stem: &str) {
139+
fn collect_events_per_thread<'a>(events: &mut dyn Iterator<Item = Event<'a>>) -> FxHashMap<u32, Vec<Event<'a>>> {
140+
let mut per_thread: FxHashMap<_, _> = Default::default();
141+
142+
for event in events {
143+
per_thread.entry(event.thread_id).or_insert(Vec::new()).push(event);
144+
}
145+
146+
per_thread
147+
}
148+
149+
pub fn run_serialization_bench<S: SerializationSink>(file_name_stem: &str, num_events: usize, num_threads: usize) {
109150
let filestem = mk_filestem(file_name_stem);
110-
let expected_events = generate_profiling_data::<S>(&filestem);
151+
generate_profiling_data::<S>(&filestem, num_events, num_threads);
152+
}
153+
154+
pub fn run_end_to_end_serialization_test<S: SerializationSink>(file_name_stem: &str, num_threads: usize) {
155+
let filestem = mk_filestem(file_name_stem);
156+
let expected_events = generate_profiling_data::<S>(&filestem, 10_000, num_threads);
111157
process_profiling_data(&filestem, &expected_events);
112158
}
113159

114160
fn pseudo_invocation<S: SerializationSink>(
115161
profiler: &Profiler<S>,
116162
random: usize,
163+
thread_id: u32,
117164
recursions_left: usize,
118165
event_ids: &[(StringId, StringId)],
119166
event_ids_as_str: &FxHashMap<StringId, &'static str>,
@@ -123,15 +170,14 @@ fn pseudo_invocation<S: SerializationSink>(
123170
return;
124171
}
125172

126-
let thread_id = (random % 3) as u32;
127-
128173
let (event_kind, event_id) = event_ids[random % event_ids.len()];
129174

130175
let _prof_guard = profiler.start_recording_interval_event(event_kind, event_id, thread_id);
131176

132177
pseudo_invocation(
133178
profiler,
134179
random,
180+
thread_id,
135181
recursions_left - 1,
136182
event_ids,
137183
event_ids_as_str,

analyzeme/tests/serialization.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,21 @@ use analyzeme::testing_common::run_end_to_end_serialization_test;
22
use measureme::{FileSerializationSink, MmapSerializationSink};
33

44
#[test]
5-
fn test_file_serialization_sink() {
6-
run_end_to_end_serialization_test::<FileSerializationSink>("file_serialization_sink_test");
5+
fn test_file_serialization_sink_1_thread() {
6+
run_end_to_end_serialization_test::<FileSerializationSink>("file_serialization_sink_test_1_thread", 1);
77
}
88

99
#[test]
10-
fn test_mmap_serialization_sink() {
11-
run_end_to_end_serialization_test::<MmapSerializationSink>("mmap_serialization_sink_test");
10+
fn test_file_serialization_sink_8_threads() {
11+
run_end_to_end_serialization_test::<FileSerializationSink>("file_serialization_sink_test_8_threads", 8);
12+
}
13+
14+
#[test]
15+
fn test_mmap_serialization_sink_1_thread() {
16+
run_end_to_end_serialization_test::<MmapSerializationSink>("mmap_serialization_sink_test_1_thread", 1);
17+
}
18+
19+
#[test]
20+
fn test_mmap_serialization_sink_8_threads() {
21+
run_end_to_end_serialization_test::<MmapSerializationSink>("mmap_serialization_sink_test_8_threads", 8);
1222
}

measureme/src/serialization.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ impl Addr {
1111
}
1212
}
1313

14-
pub trait SerializationSink: Sized {
14+
pub trait SerializationSink: Sized + Send + Sync + 'static {
1515
fn from_path(path: &Path) -> Result<Self, Box<dyn Error>>;
1616

1717
fn write_atomic<W>(&self, num_bytes: usize, write: W) -> Addr

0 commit comments

Comments
 (0)