Skip to content

Commit 06159b2

Browse files
committed
refactor(pyspy): various code refactoring for pyspy
1 parent 2f03a84 commit 06159b2

File tree

1 file changed

+43
-17
lines changed
  • pyroscope_backends/pyroscope_pyspy/src

1 file changed

+43
-17
lines changed

pyroscope_backends/pyroscope_pyspy/src/lib.rs

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ pub struct PyspyConfig {
2525
time_limit: Option<core::time::Duration>,
2626
/// Include subprocesses
2727
with_subprocesses: bool,
28-
/// todo
28+
/// Include idle time
2929
include_idle: bool,
30-
/// todo
30+
/// Detect Python GIL
3131
gil_only: bool,
32-
/// todo
32+
/// Profile native C extensions
3333
native: bool,
3434
}
3535

@@ -98,10 +98,12 @@ impl PyspyConfig {
9898
}
9999
}
100100

101+
/// Detect Python GIL
101102
pub fn gil_only(self, gil_only: bool) -> Self {
102103
PyspyConfig { gil_only, ..self }
103104
}
104105

106+
/// Profile native C extensions
105107
pub fn native(self, native: bool) -> Self {
106108
PyspyConfig { native, ..self }
107109
}
@@ -160,12 +162,12 @@ impl Backend for Pyspy {
160162
fn initialize(&mut self) -> Result<()> {
161163
// Check if Backend is Uninitialized
162164
if self.state != State::Uninitialized {
163-
return Err(PyroscopeError::new("Rbspy: Backend is already Initialized"));
165+
return Err(PyroscopeError::new("Pyspy: Backend is already Initialized"));
164166
}
165167

166168
// Check if a process ID is set
167169
if self.config.pid.is_none() {
168-
return Err(PyroscopeError::new("Rbspy: No Process ID Specified"));
170+
return Err(PyroscopeError::new("Pyspy: No Process ID Specified"));
169171
}
170172

171173
// Set duration for py-spy
@@ -197,24 +199,38 @@ impl Backend for Pyspy {
197199
fn start(&mut self) -> Result<()> {
198200
// Check if Backend is Ready
199201
if self.state != State::Ready {
200-
return Err(PyroscopeError::new("Rbspy: Backend is not Ready"));
202+
return Err(PyroscopeError::new("Pyspy: Backend is not Ready"));
201203
}
202204

205+
// set sampler state to running
203206
let running = Arc::clone(&self.running);
204-
// set running to true
205207
running.store(true, Ordering::Relaxed);
206208

209+
// create a new buffer reference
207210
let buffer = self.buffer.clone();
208211

209-
let config = self.sampler_config.clone().unwrap();
212+
// create a new sampler_config reference
213+
let config = self
214+
.sampler_config
215+
.clone()
216+
.ok_or_else(|| PyroscopeError::new("Pyspy: Sampler configuration is not set"))?;
210217

211218
self.sampler_thread = Some(std::thread::spawn(move || {
212-
let sampler = Sampler::new(config.pid.unwrap(), &config)
213-
.map_err(|e| PyroscopeError::new(&format!("Rbspy: Sampler Error: {}", e)))?;
219+
// Get PID
220+
// TODO: we are doing lots of these checks, we should probably do this once
221+
let pid = config
222+
.pid
223+
.ok_or_else(|| PyroscopeError::new("Pyspy: PID is not set"))?;
224+
225+
// Create a new pyspy sampler
226+
let sampler = Sampler::new(pid, &config)
227+
.map_err(|e| PyroscopeError::new(&format!("Pyspy: Sampler Error: {}", e)))?;
214228

215-
let isampler = sampler.take_while(|_x| running.load(Ordering::Relaxed));
229+
// Keep the sampler running until the running flag is set to false
230+
let sampler_output = sampler.take_while(|_x| running.load(Ordering::Relaxed));
216231

217-
for sample in isampler {
232+
// Collect the sampler output
233+
for sample in sampler_output {
218234
for trace in sample.traces {
219235
if !(config.include_idle || trace.active) {
220236
continue;
@@ -224,9 +240,11 @@ impl Backend for Pyspy {
224240
continue;
225241
}
226242

243+
// Convert py-spy trace to a Pyroscope trace
227244
let own_trace: StackTrace =
228245
Into::<StackTraceWrapper>::into(trace.clone()).into();
229246

247+
// Add the trace to the buffer
230248
buffer.lock()?.record(own_trace)?;
231249
}
232250
}
@@ -243,14 +261,18 @@ impl Backend for Pyspy {
243261
fn stop(&mut self) -> Result<()> {
244262
// Check if Backend is Running
245263
if self.state != State::Running {
246-
return Err(PyroscopeError::new("Rbspy: Backend is not Running"));
264+
return Err(PyroscopeError::new("Pyspy: Backend is not Running"));
247265
}
248266

249267
// set running to false
250268
self.running.store(false, Ordering::Relaxed);
251269

252270
// wait for sampler thread to finish
253-
self.sampler_thread.take().unwrap().join().unwrap()?;
271+
self.sampler_thread
272+
.take()
273+
.ok_or_else(|| PyroscopeError::new("Pyspy: Failed to unwrap Sampler Thread"))?
274+
.join()
275+
.unwrap_or_else(|_| Err(PyroscopeError::new("Pyspy: Failed to join sampler thread")))?;
254276

255277
// Set State to Running
256278
self.state = State::Ready;
@@ -261,18 +283,22 @@ impl Backend for Pyspy {
261283
fn report(&mut self) -> Result<Vec<u8>> {
262284
// Check if Backend is Running
263285
if self.state != State::Running {
264-
return Err(PyroscopeError::new("Rbspy: Backend is not Running"));
286+
return Err(PyroscopeError::new("Pyspy: Backend is not Running"));
265287
}
266288

289+
// create a new buffer reference
267290
let buffer = self.buffer.clone();
268291

269-
let v8: Vec<u8> = buffer.lock()?.to_string().into_bytes();
292+
// convert the buffer report into a byte vector
293+
let report: Vec<u8> = buffer.lock()?.to_string().into_bytes();
270294

295+
// Clear the buffer
271296
buffer.lock()?.clear();
272297

273-
Ok(v8)
298+
Ok(report)
274299
}
275300
}
301+
276302
struct StackFrameWrapper(StackFrame);
277303

278304
impl From<StackFrameWrapper> for StackFrame {

0 commit comments

Comments
 (0)