11use crate :: timestamp:: Timestamp ;
2- use crate :: { Event , LightweightEvent , ProfilingData } ;
2+ use crate :: { Event , ProfilingData } ;
33use measureme:: { Profiler , SerializationSink , StringId } ;
44use rustc_hash:: FxHashMap ;
55use 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
8198fn 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
114160fn 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,
0 commit comments