diff --git a/samply/src/linux_shared/converter.rs b/samply/src/linux_shared/converter.rs index 651ce9f0..b9a93e68 100644 --- a/samply/src/linux_shared/converter.rs +++ b/samply/src/linux_shared/converter.rs @@ -104,6 +104,12 @@ where /// already done the adjusting, either by adjusting the call chains coming from /// the kernel or by doing its own unwinding with an adjusting unwinder, call_chain_return_addresses_are_preadjusted: bool, + + /// Whether to emit JitFunctionAdd markers. + should_emit_jit_markers: bool, + + /// Whether to emit context switch markers. + should_emit_cswitch_markers: bool, } const DEFAULT_OFF_CPU_SAMPLING_INTERVAL_NS: u64 = 1_000_000; // 1ms @@ -240,6 +246,7 @@ where processes: Processes::new( profile_creation_props.reuse_threads, profile_creation_props.unlink_aux_files, + profile_creation_props.should_emit_jit_markers, ), timestamp_converter, current_sample_time: first_sample_time, @@ -267,6 +274,8 @@ where .arg_count_to_include_in_process_name, cpus, call_chain_return_addresses_are_preadjusted, + should_emit_jit_markers: profile_creation_props.should_emit_jit_markers, + should_emit_cswitch_markers: profile_creation_props.should_emit_cswitch_markers, } } @@ -957,14 +966,16 @@ where Some(idle_frame_label), ); } - cpu.notify_switch_in( - tid, - thread.thread_label(), - timestamp, - &self.timestamp_converter, - &[cpu.thread_handle, combined_thread], - &mut self.profile, - ); + if self.should_emit_cswitch_markers { + cpu.notify_switch_in_for_marker( + tid, + thread.thread_label(), + timestamp, + &self.timestamp_converter, + &[cpu.thread_handle, combined_thread], + &mut self.profile, + ); + } } } ContextSwitchRecord::Out { preempted, .. } => { @@ -975,15 +986,17 @@ where let cpu = cpus.get_mut(cpu_index as usize, &mut self.profile); self.context_switch_handler .handle_switch_out(timestamp, &mut cpu.context_switch_data); - cpu.notify_switch_out( - tid, - timestamp, - &self.timestamp_converter, - &[cpu.thread_handle, combined_thread], - thread.profile_thread, - preempted == TaskWasPreempted::Yes, - &mut self.profile, - ); + if self.should_emit_cswitch_markers { + cpu.notify_switch_out_for_marker( + tid, + timestamp, + &self.timestamp_converter, + &[cpu.thread_handle, combined_thread], + thread.profile_thread, + preempted == TaskWasPreempted::Yes, + &mut self.profile, + ); + } } } } @@ -1511,6 +1524,7 @@ where lib_handle, &mut self.jit_category_manager, &mut self.profile, + self.should_emit_jit_markers, ); } else { process.add_regular_lib_mapping( diff --git a/samply/src/linux_shared/process.rs b/samply/src/linux_shared/process.rs index 465fb031..6b3aea2e 100644 --- a/samply/src/linux_shared/process.rs +++ b/samply/src/linux_shared/process.rs @@ -59,11 +59,12 @@ where thread_recycler: Option, jit_function_recycler: Option, unlink_aux_files: bool, + should_emit_jit_markers: bool, ) -> Self { Self { profile_process: process_handle, unwinder: U::default(), - jitdump_manager: JitDumpManager::new(unlink_aux_files), + jitdump_manager: JitDumpManager::new(unlink_aux_files, should_emit_jit_markers), lib_mapping_ops: Default::default(), name: name.clone(), pid, @@ -207,8 +208,7 @@ where None }; - let jitdump_manager = - std::mem::replace(&mut self.jitdump_manager, JitDumpManager::new(false)); + let jitdump_manager = self.jitdump_manager; let mut jitdump_ops = jitdump_manager.finish( jit_category_manager, profile, @@ -298,14 +298,17 @@ where mut lib_handle: LibraryHandle, jit_category_manager: &mut JitCategoryManager, profile: &mut Profile, + should_add_marker: bool, ) { - let main_thread = self.threads.main_thread.profile_thread; - let timing = MarkerTiming::Instant(profile_timestamp); - let name = match symbol_name { - Some(name) => profile.intern_string(name), - None => profile.intern_string(""), - }; - profile.add_marker(main_thread, timing, JitFunctionAddMarker(name)); + if should_add_marker { + let main_thread = self.threads.main_thread.profile_thread; + let timing = MarkerTiming::Instant(profile_timestamp); + let name = match symbol_name { + Some(name) => profile.intern_string(name), + None => profile.intern_string(""), + }; + profile.add_marker(main_thread, timing, JitFunctionAddMarker(name)); + } if let (Some(name), Some(recycler)) = (symbol_name, self.jit_function_recycler.as_mut()) { let code_size = (end_address - start_address) as u32; diff --git a/samply/src/linux_shared/processes.rs b/samply/src/linux_shared/processes.rs index 21a33be1..36234a29 100644 --- a/samply/src/linux_shared/processes.rs +++ b/samply/src/linux_shared/processes.rs @@ -28,13 +28,16 @@ where /// Whether aux files (like jitdump) should be unlinked on open unlink_aux_data: bool, + + /// Whether to emit JitFunctionAdd markers. + should_emit_jit_markers: bool, } impl Processes where U: Unwinder + Default, { - pub fn new(allow_reuse: bool, unlink_aux_data: bool) -> Self { + pub fn new(allow_reuse: bool, unlink_aux_data: bool, should_emit_jit_markers: bool) -> Self { let process_recycler = if allow_reuse { Some(ProcessRecycler::new()) } else { @@ -45,6 +48,7 @@ where process_recycler, process_sample_datas: Vec::new(), unlink_aux_data, + should_emit_jit_markers, } } @@ -78,6 +82,7 @@ where Some(thread_recycler), Some(jit_function_recycler), self.unlink_aux_data, + self.should_emit_jit_markers, ); return entry.insert(process); } @@ -113,6 +118,7 @@ where thread_recycler, jit_function_recycler, self.unlink_aux_data, + self.should_emit_jit_markers, ); entry.insert(process) } @@ -164,6 +170,7 @@ where thread_recycler, jit_function_recycler, self.unlink_aux_data, + self.should_emit_jit_markers, ) }) } diff --git a/samply/src/mac/task_profiler.rs b/samply/src/mac/task_profiler.rs index ab1be183..50cb9ecf 100644 --- a/samply/src/mac/task_profiler.rs +++ b/samply/src/mac/task_profiler.rs @@ -303,7 +303,10 @@ impl TaskProfiler { ignored_errors: Vec::new(), unwinder: UnwinderNative::new(), path_receiver, - jitdump_manager: JitDumpManager::new(profile_creation_props.unlink_aux_files), + jitdump_manager: JitDumpManager::new( + profile_creation_props.unlink_aux_files, + profile_creation_props.should_emit_jit_markers, + ), marker_file_paths: Vec::new(), lib_mapping_ops: Default::default(), unresolved_samples: Default::default(), diff --git a/samply/src/main.rs b/samply/src/main.rs index 86193ff7..79b09da1 100644 --- a/samply/src/main.rs +++ b/samply/src/main.rs @@ -371,6 +371,14 @@ pub struct ProfileCreationArgs { #[arg(long)] per_cpu_threads: bool, + /// Emit a JitFunctionAdd markers when a JIT function is added. + #[arg(long)] + jit_markers: bool, + + /// Emit context switch markers. + #[arg(long)] + cswitch_markers: bool, + /// Include up to command line arguments in the process name. /// This can help differentiate processes if the same executable is used /// for different types of programs. And in --reuse-threads mode it @@ -541,6 +549,8 @@ impl ImportArgs { arg_count_to_include_in_process_name: self.profile_creation_args.include_args, override_arch: self.override_arch.clone(), unstable_presymbolicate: self.profile_creation_args.unstable_presymbolicate, + should_emit_jit_markers: self.profile_creation_args.jit_markers, + should_emit_cswitch_markers: self.profile_creation_args.cswitch_markers, coreclr: to_coreclr_profile_props(&self.coreclr), #[cfg(target_os = "windows")] unknown_event_markers: self.profile_creation_args.unknown_event_markers, @@ -664,6 +674,8 @@ impl RecordArgs { arg_count_to_include_in_process_name: self.profile_creation_args.include_args, override_arch: None, unstable_presymbolicate: self.profile_creation_args.unstable_presymbolicate, + should_emit_jit_markers: self.profile_creation_args.jit_markers, + should_emit_cswitch_markers: self.profile_creation_args.cswitch_markers, coreclr: to_coreclr_profile_props(&self.coreclr), #[cfg(target_os = "windows")] unknown_event_markers: self.profile_creation_args.unknown_event_markers, diff --git a/samply/src/shared/jitdump_manager.rs b/samply/src/shared/jitdump_manager.rs index 39e3ff23..1bb0566f 100644 --- a/samply/src/shared/jitdump_manager.rs +++ b/samply/src/shared/jitdump_manager.rs @@ -20,14 +20,16 @@ pub struct JitDumpManager { pending_jitdump_paths: Vec<(ThreadHandle, PathBuf, Vec)>, processors: Vec, unlink_after_open: bool, + should_emit_jit_markers: bool, } impl JitDumpManager { - pub fn new(unlink_after_open: bool) -> Self { + pub fn new(unlink_after_open: bool, should_emit_jit_markers: bool) -> Self { JitDumpManager { pending_jitdump_paths: Vec::new(), processors: Vec::new(), unlink_after_open, + should_emit_jit_markers, } } @@ -83,6 +85,7 @@ impl JitDumpManager { profile, recycler.as_deref_mut(), timestamp_converter, + self.should_emit_jit_markers, ); } } @@ -143,6 +146,7 @@ impl SingleJitDumpProcessor { profile: &mut Profile, mut recycler: Option<&mut JitFunctionRecycler>, timestamp_converter: &TimestampConverter, + should_add_marker: bool, ) { let Some(reader) = self.reader.as_mut() else { return; @@ -186,13 +190,16 @@ impl SingleJitDumpProcessor { name: symbol_name.to_owned(), }); - let timestamp = timestamp_converter.convert_time(raw_jitdump_record.timestamp); - let symbol_name_handle = profile.intern_string(symbol_name); - profile.add_marker( - self.thread_handle, - MarkerTiming::Instant(timestamp), - JitFunctionAddMarker(symbol_name_handle), - ); + if should_add_marker { + let timestamp = + timestamp_converter.convert_time(raw_jitdump_record.timestamp); + let symbol_name_handle = profile.intern_string(symbol_name); + profile.add_marker( + self.thread_handle, + MarkerTiming::Instant(timestamp), + JitFunctionAddMarker(symbol_name_handle), + ); + } let (lib_handle, relative_address_at_start) = if let Some(recycler) = recycler.as_deref_mut() { diff --git a/samply/src/shared/per_cpu.rs b/samply/src/shared/per_cpu.rs index 5a052e1a..d5b265f3 100644 --- a/samply/src/shared/per_cpu.rs +++ b/samply/src/shared/per_cpu.rs @@ -19,7 +19,7 @@ pub struct Cpu { pub name: StringHandle, pub thread_handle: ThreadHandle, pub context_switch_data: ThreadContextSwitchData, - pub current_tid: Option<(i32, StringHandle, u64)>, + current_tid: Option<(i32, StringHandle, u64)>, } impl Cpu { @@ -33,7 +33,7 @@ impl Cpu { } #[allow(clippy::too_many_arguments)] - pub fn notify_switch_in( + pub fn notify_switch_in_for_marker( &mut self, tid: i32, thread_name: StringHandle, @@ -60,7 +60,7 @@ impl Cpu { } #[allow(clippy::too_many_arguments)] - pub fn notify_switch_out( + pub fn notify_switch_out_for_marker( &mut self, tid: i32, // tid that is being switched away from timestamp: u64, diff --git a/samply/src/shared/recording_props.rs b/samply/src/shared/recording_props.rs index 24e09c6c..66ea5cdf 100644 --- a/samply/src/shared/recording_props.rs +++ b/samply/src/shared/recording_props.rs @@ -95,6 +95,12 @@ pub struct ProfileCreationProps { /// Time range to include, relative to start of recording. #[allow(dead_code)] pub time_range: Option<(std::time::Duration, std::time::Duration)>, + /// Whether to emit "JitFunctionAdd" markers. + #[allow(dead_code)] + pub should_emit_jit_markers: bool, + /// Whether to emit context switch markers. + #[allow(dead_code)] + pub should_emit_cswitch_markers: bool, } impl ProfileCreationProps { diff --git a/samply/src/windows/profile_context.rs b/samply/src/windows/profile_context.rs index 778a1df4..9ec3755a 100644 --- a/samply/src/windows/profile_context.rs +++ b/samply/src/windows/profile_context.rs @@ -1630,18 +1630,20 @@ impl ProfileContext { self.context_switch_handler .handle_switch_out(timestamp_raw, &mut cpu.context_switch_data); - // TODO: Find out if this actually is the right way to check whether a thread - // has been pre-empted. - let preempted = wait_reason == 0 || wait_reason == 32; // "Executive" | "WrPreempted" - cpu.notify_switch_out( - old_tid as i32, - timestamp_raw, - &self.timestamp_converter, - &[cpu.thread_handle, combined_thread], - old_thread.handle, - preempted, - &mut self.profile, - ); + if self.profile_creation_props.should_emit_cswitch_markers { + // TODO: Find out if this actually is the right way to check whether a thread + // has been pre-empted. + let preempted = wait_reason == 0 || wait_reason == 32; // "Executive" | "WrPreempted" + cpu.notify_switch_out_for_marker( + old_tid as i32, + timestamp_raw, + &self.timestamp_converter, + &[cpu.thread_handle, combined_thread], + old_thread.handle, + preempted, + &mut self.profile, + ); + } } } @@ -1705,14 +1707,16 @@ impl ProfileContext { 0, ); } - cpu.notify_switch_in( - new_tid as i32, - new_thread.thread_label(), - timestamp_raw, - &self.timestamp_converter, - &[cpu.thread_handle, combined_thread], - &mut self.profile, - ); + if self.profile_creation_props.should_emit_cswitch_markers { + cpu.notify_switch_in_for_marker( + new_tid as i32, + new_thread.thread_label(), + timestamp_raw, + &self.timestamp_converter, + &[cpu.thread_handle, combined_thread], + &mut self.profile, + ); + } } } } @@ -1777,13 +1781,15 @@ impl ProfileContext { let lib = &mut self.js_jit_lib; let info = LibMappingInfo::new_jit_function(lib.lib_handle(), category, js_frame); - let name_handle = self.profile.intern_string(&method_name); - let timestamp = self.timestamp_converter.convert_time(timestamp_raw); - self.profile.add_marker( - process.main_thread_handle, - MarkerTiming::Instant(timestamp), - JitFunctionAddMarker(name_handle), - ); + if self.profile_creation_props.should_emit_jit_markers { + let name_handle = self.profile.intern_string(&method_name); + let timestamp = self.timestamp_converter.convert_time(timestamp_raw); + self.profile.add_marker( + process.main_thread_handle, + MarkerTiming::Instant(timestamp), + JitFunctionAddMarker(name_handle), + ); + } process.add_jit_function( timestamp_raw,