11use crate :: prelude:: * ;
22use crate :: run:: runner:: helpers:: run_command_with_log_pipe:: run_command_with_log_pipe_and_callback;
33use crate :: run:: runner:: helpers:: setup:: run_with_sudo;
4+ use crate :: run:: runner:: valgrind:: helpers:: ignored_objects_path:: get_objects_path_to_ignore;
5+ use crate :: run:: runner:: valgrind:: helpers:: perf_maps:: harvest_perf_maps_for_pids;
46use anyhow:: Context ;
57use fifo:: { PerfFifo , RunnerFifo } ;
68use futures:: stream:: FuturesUnordered ;
79use metadata:: PerfMetadata ;
810use perf_map:: ProcessSymbols ;
911use procfs:: process:: MMPermissions ;
1012use shared:: Command as FifoCommand ;
13+ use std:: collections:: HashSet ;
1114use std:: path:: PathBuf ;
1215use std:: process:: Command ;
1316use std:: time:: Duration ;
@@ -76,10 +79,23 @@ impl PerfRunner {
7679 . prefix ( PERF_DATA_PREFIX )
7780 . tempfile_in ( & self . perf_dir ) ?;
7881
82+ // Detect the mode based on the command to be executed
83+ let cg_mode = if bench_cmd. contains ( "cargo" ) {
84+ "dwarf"
85+ } else if bench_cmd. contains ( "pytest" ) {
86+ "fp"
87+ } else {
88+ panic ! (
89+ "Perf not supported. Failed to detect call graph mode for command: {}" ,
90+ bench_cmd
91+ )
92+ } ;
93+ debug ! ( "Using call graph mode: {}" , cg_mode) ;
94+
7995 cmd. args ( [
8096 "-c" ,
8197 & format ! (
82- "perf record --quiet --user-callchains --freq=999 --switch-output --control=fifo:{},{} --delay=-1 -g --call-graph=dwarf --output={} -- {bench_cmd}" ,
98+ "perf record --quiet --user-callchains --freq=999 --switch-output --control=fifo:{},{} --delay=-1 -g --call-graph={cg_mode} --output={} -- {bench_cmd}" ,
8399 perf_fifo. ctl_fifo_path. to_string_lossy( ) ,
84100 perf_fifo. ack_fifo_path. to_string_lossy( ) ,
85101 perf_file. path( ) . to_string_lossy( )
@@ -125,7 +141,7 @@ impl PerfRunner {
125141 let dst_path = profile_folder. join ( dst_file_name) ;
126142 tokio:: fs:: copy ( src_path, dst_path) . await ?;
127143
128- Ok :: < _ , anyhow:: Error > ( ( ) )
144+ Ok :: < _ , anyhow:: Error > ( pid )
129145 } )
130146 } )
131147 . collect :: < FuturesUnordered < _ > > ( ) ;
@@ -139,7 +155,16 @@ impl PerfRunner {
139155 bench_data. bench_count( ) ,
140156 "Benchmark count mismatch"
141157 ) ;
142- let _ = futures:: future:: try_join_all ( copy_tasks) . await ?;
158+
159+ // Harvest the perf maps generated by python. This will copy the perf
160+ // maps from /tmp to the profile folder. We have to write our own perf
161+ // maps to these files AFTERWARDS, otherwise it'll be overwritten!
162+ let perf_map_pids = futures:: future:: try_join_all ( copy_tasks)
163+ . await ?
164+ . into_iter ( )
165+ . filter_map ( Result :: ok)
166+ . collect :: < HashSet < _ > > ( ) ;
167+ harvest_perf_maps_for_pids ( profile_folder, & perf_map_pids) . await ?;
143168
144169 // Append perf maps, unwind info and other metadata
145170 bench_data. save_to ( profile_folder) . unwrap ( ) ;
@@ -272,6 +297,27 @@ impl BenchmarkData {
272297 let metadata = PerfMetadata {
273298 integration : self . integration . clone ( ) ,
274299 bench_order_by_pid : self . bench_order_by_pid . clone ( ) ,
300+ ignored_modules : {
301+ let mut to_ignore = vec ! [ ] ;
302+
303+ // Check if any of the ignored modules has been loaded in the process
304+ for ignore_path in get_objects_path_to_ignore ( ) {
305+ for proc in self . symbols_by_pid . values ( ) {
306+ if let Some ( mapping) = proc. module_mapping ( & ignore_path) {
307+ let ( Some ( ( base_addr, _) ) , Some ( ( _, end_addr) ) ) = (
308+ mapping. iter ( ) . min_by_key ( |( base_addr, _) | base_addr) ,
309+ mapping. iter ( ) . max_by_key ( |( _, end_addr) | end_addr) ,
310+ ) else {
311+ continue ;
312+ } ;
313+
314+ to_ignore. push ( ( ignore_path. clone ( ) , * base_addr, * end_addr) ) ;
315+ }
316+ }
317+ }
318+
319+ to_ignore
320+ } ,
275321 } ;
276322 metadata. save_to ( & path) . unwrap ( ) ;
277323
0 commit comments