diff --git a/profiling/src/profiling/mod.rs b/profiling/src/profiling/mod.rs index 389fd35a83..52ab137901 100644 --- a/profiling/src/profiling/mod.rs +++ b/profiling/src/profiling/mod.rs @@ -652,6 +652,7 @@ pub enum UploadMessage { } const COW_EVAL: Cow = Cow::Borrowed("[eval]"); +const COW_PROFILER_STACK_WALK: Cow = Cow::Borrowed("[profiler stack walk]"); const DDPROF_TIME: &str = "ddprof_time"; const DDPROF_UPLOAD: &str = "ddprof_upload"; @@ -908,12 +909,10 @@ impl Profiler { pub fn collect_time(&self, execute_data: *mut zend_execute_data, interrupt_count: u32) { // todo: should probably exclude the wall and CPU time used by collecting the sample. let interrupt_count = interrupt_count as i64; - let result = collect_stack_sample(execute_data); + let (result, wall_time, cpu_time) = self.collect_stack_sample_with_timeline(execute_data); match result { Ok(frames) => { let depth = frames.len(); - let (wall_time, cpu_time) = CLOCKS.with_borrow_mut(Clocks::rotate_clocks); - let labels = Profiler::common_labels(0); let n_labels = labels.len(); @@ -956,7 +955,7 @@ impl Profiler { alloc_size: i64, interrupt_count: Option, ) { - let result = collect_stack_sample(execute_data); + let (result, wall_time, cpu_time) = self.collect_stack_sample_with_timeline(execute_data); match result { Ok(frames) => { let depth = frames.len(); @@ -964,7 +963,6 @@ impl Profiler { // Optionally collect time data when interrupt_count is provided let (interrupt_count, wall_time, cpu_time, timestamp) = if let Some(count) = interrupt_count { - let (wall_time, cpu_time) = CLOCKS.with_borrow_mut(Clocks::rotate_clocks); let timestamp = self.get_timeline_timestamp(); (count as i64, wall_time, cpu_time, timestamp) } else { @@ -1009,7 +1007,7 @@ impl Profiler { exception: String, message: Option, ) { - let result = collect_stack_sample(execute_data); + let (result, _wall_time, _cpu_time) = self.collect_stack_sample_with_timeline(execute_data); match result { Ok(frames) => { let depth = frames.len(); @@ -1409,7 +1407,7 @@ impl Profiler { where F: FnOnce(&mut SampleValues), { - let result = collect_stack_sample(execute_data); + let (result, _wall_time, _cpu_time) = self.collect_stack_sample_with_timeline(execute_data); match result { Ok(frames) => { let depth = frames.len(); @@ -1543,6 +1541,43 @@ impl Profiler { }, } } + + fn collect_stack_sample_with_timeline( + &self, + execute_data: *mut zend_execute_data, + ) -> (Result, CollectStackSampleError>, i64, i64) { + let (wall_time, cpu_time) = CLOCKS.with_borrow_mut(Clocks::rotate_clocks); + let result = collect_stack_sample(execute_data); + let (stack_walk_wall_time, stack_walk_cpu_time) = + CLOCKS.with_borrow_mut(Clocks::rotate_clocks); + + let timestamp = self.get_timeline_timestamp(); + let labels = Profiler::common_labels(0); + let n_labels = labels.len(); + match self.prepare_and_send_message( + vec![ZendFrame { + function: COW_PROFILER_STACK_WALK, + file: None, + line: 0, + }], + SampleValues { + wall_time: stack_walk_wall_time, + cpu_time: stack_walk_cpu_time, + ..Default::default() + }, + labels, + timestamp, + ) { + Ok(_) => { + trace!("Sent stack walk sample with {n_labels} labels to profiler.") + } + Err(err) => { + warn!("Failed to send stack walk sample with {n_labels} labels to profiler: {err}") + } + } + + (result, wall_time, cpu_time) + } } pub struct JoinError {