Skip to content

Commit 58dbbd9

Browse files
Improve SerializationSink benchmarks and tests.
1 parent 8367ec6 commit 58dbbd9

File tree

4 files changed

+111
-36
lines changed

4 files changed

+111
-36
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: 74 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,16 @@ fn mk_filestem(file_name_stem: &str) -> PathBuf {
1818
}
1919

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

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

26-
let event_ids = &[
30+
let event_ids = vec![
2731
(
2832
profiler.alloc_string("Generic"),
2933
profiler.alloc_string("SomeGenericActivity"),
@@ -38,20 +42,33 @@ fn generate_profiling_data<S: SerializationSink>(filestem: &Path) -> Vec<Event<'
3842
event_ids_as_str.insert(event_ids[1].0, "Query");
3943
event_ids_as_str.insert(event_ids[1].1, "SomeQuery");
4044

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

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

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

5673
// An example of allocating the string contents of an event id that has
5774
// already been used
@@ -84,34 +101,65 @@ fn check_profiling_data(
84101
) {
85102
let mut count = 0;
86103

104+
// This assertion makes sure that the ExactSizeIterator impl works as expected.
87105
assert_eq!(
88106
(num_expected_events, Some(num_expected_events)),
89107
actual_events.size_hint()
90108
);
91109

92-
for (actual_event, expected_event) in actual_events.zip(expected_events) {
93-
assert_eq!(actual_event.event_kind, expected_event.event_kind);
94-
assert_eq!(actual_event.label, expected_event.label);
95-
assert_eq!(actual_event.additional_data, expected_event.additional_data);
96-
assert_eq!(
97-
actual_event.timestamp.is_instant(),
98-
expected_event.timestamp.is_instant()
99-
);
110+
let actual_events_per_thread = collect_events_per_thread(actual_events);
111+
let expected_events_per_thread = collect_events_per_thread(expected_events);
112+
113+
let thread_ids: Vec<_> = actual_events_per_thread.keys().collect();
114+
assert_eq!(thread_ids, expected_events_per_thread.keys().collect::<Vec<_>>());
100115

101-
count += 1;
116+
for thread_id in thread_ids {
117+
let actual_events = &actual_events_per_thread[thread_id];
118+
let expected_events = &expected_events_per_thread[thread_id];
119+
120+
assert_eq!(actual_events.len(), expected_events.len());
121+
122+
for (actual_event, expected_event) in actual_events.iter().zip(expected_events.iter()) {
123+
assert_eq!(actual_event.event_kind, expected_event.event_kind);
124+
assert_eq!(actual_event.label, expected_event.label);
125+
assert_eq!(actual_event.additional_data, expected_event.additional_data);
126+
assert_eq!(
127+
actual_event.timestamp.is_instant(),
128+
expected_event.timestamp.is_instant()
129+
);
130+
131+
count += 1;
132+
}
102133
}
134+
103135
assert_eq!(count, num_expected_events);
104136
}
105137

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

112159
fn pseudo_invocation<S: SerializationSink>(
113160
profiler: &Profiler<S>,
114161
random: usize,
162+
thread_id: u64,
115163
recursions_left: usize,
116164
event_ids: &[(StringId, StringId)],
117165
event_ids_as_str: &FxHashMap<StringId, &'static str>,
@@ -121,15 +169,14 @@ fn pseudo_invocation<S: SerializationSink>(
121169
return;
122170
}
123171

124-
let thread_id = (random % 3) as u64;
125-
126172
let (event_kind, event_id) = event_ids[random % event_ids.len()];
127173

128174
let _prof_guard = profiler.start_recording_interval_event(event_kind, event_id, thread_id);
129175

130176
pseudo_invocation(
131177
profiler,
132178
random,
179+
thread_id,
133180
recursions_left - 1,
134181
event_ids,
135182
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)