@@ -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+
276302struct StackFrameWrapper ( StackFrame ) ;
277303
278304impl From < StackFrameWrapper > for StackFrame {
0 commit comments