1
1
use crate :: timestamp:: Timestamp ;
2
- use crate :: { Event , LightweightEvent , ProfilingData } ;
2
+ use crate :: { Event , ProfilingData } ;
3
3
use measureme:: { Profiler , SerializationSink , StringId } ;
4
4
use rustc_hash:: FxHashMap ;
5
5
use std:: borrow:: Cow ;
@@ -19,12 +19,16 @@ fn mk_filestem(file_name_stem: &str) -> PathBuf {
19
19
}
20
20
21
21
// 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 > > {
23
27
let profiler = Arc :: new ( Profiler :: < S > :: new ( Path :: new ( filestem) ) . unwrap ( ) ) ;
24
28
25
29
let event_id_reserved = StringId :: reserved ( 42 ) ;
26
30
27
- let event_ids = & [
31
+ let event_ids = vec ! [
28
32
(
29
33
profiler. alloc_string( "Generic" ) ,
30
34
profiler. alloc_string( "SomeGenericActivity" ) ,
@@ -39,20 +43,33 @@ fn generate_profiling_data<S: SerializationSink>(filestem: &Path) -> Vec<Event<'
39
43
event_ids_as_str. insert ( event_ids[ 1 ] . 0 , "Query" ) ;
40
44
event_ids_as_str. insert ( event_ids[ 1 ] . 1 , "SomeQuery" ) ;
41
45
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 ( ) ;
43
50
44
- for i in 0 .. 10_000 {
45
- // Allocate some invocation stacks
51
+ std :: thread :: spawn ( move || {
52
+ let mut expected_events = Vec :: new ( ) ;
46
53
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 ( ) ;
56
73
57
74
// An example of allocating the string contents of an event id that has
58
75
// already been used
@@ -67,53 +84,83 @@ fn process_profiling_data(filestem: &Path, expected_events: &[Event<'static>]) {
67
84
let profiling_data = ProfilingData :: new ( filestem) . unwrap ( ) ;
68
85
69
86
check_profiling_data (
70
- & mut profiling_data. iter ( ) ,
87
+ & mut profiling_data. iter ( ) . map ( |e| e . to_event ( ) ) ,
71
88
& mut expected_events. iter ( ) . cloned ( ) ,
72
89
expected_events. len ( ) ,
73
90
) ;
74
91
check_profiling_data (
75
- & mut profiling_data. iter ( ) . rev ( ) ,
92
+ & mut profiling_data. iter ( ) . rev ( ) . map ( |e| e . to_event ( ) ) ,
76
93
& mut expected_events. iter ( ) . rev ( ) . cloned ( ) ,
77
94
expected_events. len ( ) ,
78
95
) ;
79
96
}
80
97
81
98
fn check_profiling_data (
82
- actual_lightweight_events : & mut dyn Iterator < Item = LightweightEvent < ' _ > > ,
99
+ actual_events : & mut dyn Iterator < Item = Event < ' _ > > ,
83
100
expected_events : & mut dyn Iterator < Item = Event < ' _ > > ,
84
101
num_expected_events : usize ,
85
102
) {
86
103
let mut count = 0 ;
87
104
105
+ // This assertion makes sure that the ExactSizeIterator impl works as expected.
88
106
assert_eq ! (
89
107
( num_expected_events, Some ( num_expected_events) ) ,
90
- actual_lightweight_events . size_hint( )
108
+ actual_events . size_hint( )
91
109
) ;
92
110
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
+ }
104
134
}
135
+
105
136
assert_eq ! ( count, num_expected_events) ;
106
137
}
107
138
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 ) {
109
150
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) ;
111
157
process_profiling_data ( & filestem, & expected_events) ;
112
158
}
113
159
114
160
fn pseudo_invocation < S : SerializationSink > (
115
161
profiler : & Profiler < S > ,
116
162
random : usize ,
163
+ thread_id : u32 ,
117
164
recursions_left : usize ,
118
165
event_ids : & [ ( StringId , StringId ) ] ,
119
166
event_ids_as_str : & FxHashMap < StringId , & ' static str > ,
@@ -123,15 +170,14 @@ fn pseudo_invocation<S: SerializationSink>(
123
170
return ;
124
171
}
125
172
126
- let thread_id = ( random % 3 ) as u32 ;
127
-
128
173
let ( event_kind, event_id) = event_ids[ random % event_ids. len ( ) ] ;
129
174
130
175
let _prof_guard = profiler. start_recording_interval_event ( event_kind, event_id, thread_id) ;
131
176
132
177
pseudo_invocation (
133
178
profiler,
134
179
random,
180
+ thread_id,
135
181
recursions_left - 1 ,
136
182
event_ids,
137
183
event_ids_as_str,
0 commit comments