@@ -11,6 +11,7 @@ use move_core_types::{
1111 identifier:: { IdentStr , Identifier } ,
1212} ;
1313use move_trace_format:: format:: { MoveTraceReader , TraceEvent } ;
14+ use rayon:: prelude:: * ;
1415use serde:: { Deserialize , Serialize } ;
1516use std:: {
1617 collections:: BTreeMap ,
@@ -62,7 +63,7 @@ pub struct TraceMap {
6263/// Trait for types that consume Move VM trace events. Implementors only need to provide
6364/// `record_instruction`; directory iteration, file reading, and trace event walking are
6465/// provided as default methods.
65- pub trait TraceConsumer : Default {
66+ pub trait TraceConsumer : Default + Send {
6667 fn record_instruction (
6768 & mut self ,
6869 test_name : & str ,
@@ -72,6 +73,8 @@ pub trait TraceConsumer: Default {
7273 pc : u64 ,
7374 ) ;
7475
76+ fn merge ( self , other : Self ) -> Self ;
77+
7578 fn ingest_trace < R : Read > (
7679 mut self ,
7780 test_name : & str ,
@@ -102,21 +105,30 @@ pub trait TraceConsumer: Default {
102105 self
103106 }
104107
105- fn ingest_trace_dir < P : AsRef < Path > + Debug > ( mut self , dirname : P ) -> Self {
106- for entry in std:: fs:: read_dir ( & dirname) . unwrap ( ) {
107- let entry = entry. unwrap ( ) ;
108- let path = entry. path ( ) ;
109- if path. is_file ( ) {
110- let file = File :: open ( & path)
108+ fn ingest_trace_dir < P : AsRef < Path > + Debug > ( self , dirname : P ) -> Self {
109+ let entries: Vec < _ > = std:: fs:: read_dir ( & dirname)
110+ . unwrap ( )
111+ . filter_map ( |e| {
112+ let path = e. unwrap ( ) . path ( ) ;
113+ path. is_file ( ) . then_some ( path)
114+ } )
115+ . collect ( ) ;
116+
117+ entries
118+ . par_iter ( )
119+ . map ( |path| {
120+ let file = File :: open ( path)
111121 . unwrap_or_else ( |e| panic ! ( "Unable to open trace file '{:?}': {}" , path, e) ) ;
112- let move_trace_reader =
113- MoveTraceReader :: new ( file) . expect ( "Unable to read trace file" ) ;
114- let test_name = path. file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) ;
115- let test_name = test_name. replace ( "__" , "::" ) ;
116- self = self . ingest_trace ( & test_name, move_trace_reader) ;
117- }
118- }
119- self
122+ let reader = MoveTraceReader :: new ( file) . expect ( "Unable to read trace file" ) ;
123+ let test_name = path
124+ . file_name ( )
125+ . unwrap ( )
126+ . to_str ( )
127+ . unwrap ( )
128+ . replace ( "__" , "::" ) ;
129+ Self :: default ( ) . ingest_trace ( & test_name, reader)
130+ } )
131+ . reduce ( Self :: default, Self :: merge)
120132 }
121133
122134 fn from_trace_dir < P : AsRef < Path > + Debug > ( dirname : P ) -> Self {
@@ -135,6 +147,28 @@ impl TraceConsumer for CoverageMap {
135147 ) {
136148 self . insert ( test_name, module_addr, module_name, func_name, pc) ;
137149 }
150+
151+ fn merge ( mut self , other : Self ) -> Self {
152+ for ( exec_id, other_exec_map) in other. exec_maps {
153+ let entry = self
154+ . exec_maps
155+ . entry ( exec_id)
156+ . or_insert_with ( || ExecCoverageMap :: new ( String :: new ( ) ) ) ;
157+ for ( ( addr, name) , other_module_map) in other_exec_map. module_maps {
158+ let module_entry = entry
159+ . module_maps
160+ . entry ( ( addr, name. clone ( ) ) )
161+ . or_insert_with ( || ModuleCoverageMap :: new ( addr, name) ) ;
162+ for ( func_name, func_map) in other_module_map. function_maps {
163+ let func_entry = module_entry. function_maps . entry ( func_name) . or_default ( ) ;
164+ for ( pc, count) in func_map {
165+ * func_entry. entry ( pc) . or_insert ( 0 ) += count;
166+ }
167+ }
168+ }
169+ }
170+ self
171+ }
138172}
139173
140174impl TraceConsumer for TraceMap {
@@ -148,6 +182,16 @@ impl TraceConsumer for TraceMap {
148182 ) {
149183 self . insert ( test_name, module_addr, module_name, func_name, pc) ;
150184 }
185+
186+ fn merge ( mut self , other : Self ) -> Self {
187+ for ( exec_id, other_entries) in other. exec_maps {
188+ self . exec_maps
189+ . entry ( exec_id)
190+ . or_default ( )
191+ . extend ( other_entries) ;
192+ }
193+ self
194+ }
151195}
152196
153197impl CoverageMap {
0 commit comments