@@ -207,6 +207,7 @@ def __init__(self, frequency, options, sdk_info, capture_func):
207
207
self .pid = None # type: Optional[int]
208
208
209
209
self .running = False
210
+ self .soft_shutdown = False
210
211
211
212
self .new_profiles = deque (maxlen = 128 ) # type: Deque[ContinuousProfile]
212
213
self .active_profiles = set () # type: Set[ContinuousProfile]
@@ -288,24 +289,23 @@ def profiler_id(self):
288
289
return self .buffer .profiler_id
289
290
290
291
def make_sampler (self ):
291
- # type: () -> Callable[..., None ]
292
+ # type: () -> Callable[..., bool ]
292
293
cwd = os .getcwd ()
293
294
294
295
cache = LRUCache (max_size = 256 )
295
296
296
297
if self .lifecycle == "trace" :
297
298
298
299
def _sample_stack (* args , ** kwargs ):
299
- # type: (*Any, **Any) -> None
300
+ # type: (*Any, **Any) -> bool
300
301
"""
301
302
Take a sample of the stack on all the threads in the process.
302
303
This should be called at a regular interval to collect samples.
303
304
"""
304
305
305
306
# no profiles taking place, so we can stop early
306
307
if not self .new_profiles and not self .active_profiles :
307
- self .running = False
308
- return
308
+ return True
309
309
310
310
# This is the number of profiles we want to pop off.
311
311
# It's possible another thread adds a new profile to
@@ -328,7 +328,7 @@ def _sample_stack(*args, **kwargs):
328
328
# For some reason, the frame we get doesn't have certain attributes.
329
329
# When this happens, we abandon the current sample as it's bad.
330
330
capture_internal_exception (sys .exc_info ())
331
- return
331
+ return False
332
332
333
333
# Move the new profiles into the active_profiles set.
334
334
#
@@ -345,9 +345,7 @@ def _sample_stack(*args, **kwargs):
345
345
inactive_profiles = []
346
346
347
347
for profile in self .active_profiles :
348
- if profile .active :
349
- pass
350
- else :
348
+ if not profile .active :
351
349
# If a profile is marked inactive, we buffer it
352
350
# to `inactive_profiles` so it can be removed.
353
351
# We cannot remove it here as it would result
@@ -360,10 +358,12 @@ def _sample_stack(*args, **kwargs):
360
358
if self .buffer is not None :
361
359
self .buffer .write (ts , sample )
362
360
361
+ return False
362
+
363
363
else :
364
364
365
365
def _sample_stack (* args , ** kwargs ):
366
- # type: (*Any, **Any) -> None
366
+ # type: (*Any, **Any) -> bool
367
367
"""
368
368
Take a sample of the stack on all the threads in the process.
369
369
This should be called at a regular interval to collect samples.
@@ -380,19 +380,21 @@ def _sample_stack(*args, **kwargs):
380
380
# For some reason, the frame we get doesn't have certain attributes.
381
381
# When this happens, we abandon the current sample as it's bad.
382
382
capture_internal_exception (sys .exc_info ())
383
- return
383
+ return False
384
384
385
385
if self .buffer is not None :
386
386
self .buffer .write (ts , sample )
387
387
388
+ return False
389
+
388
390
return _sample_stack
389
391
390
392
def run (self ):
391
393
# type: () -> None
392
394
last = time .perf_counter ()
393
395
394
396
while self .running :
395
- self .sampler ()
397
+ self .soft_shutdown = self . sampler ()
396
398
397
399
# some time may have elapsed since the last time
398
400
# we sampled, so we need to account for that and
@@ -401,6 +403,15 @@ def run(self):
401
403
if elapsed < self .interval :
402
404
thread_sleep (self .interval - elapsed )
403
405
406
+ # the soft shutdown happens here to give it a chance
407
+ # for the profiler to be reused
408
+ if self .soft_shutdown :
409
+ self .running = False
410
+
411
+ # make sure to explicitly exit the profiler here or there might
412
+ # be multiple profilers at once
413
+ break
414
+
404
415
# after sleeping, make sure to take the current
405
416
# timestamp so we can use it next iteration
406
417
last = time .perf_counter ()
@@ -429,6 +440,8 @@ def __init__(self, frequency, options, sdk_info, capture_func):
429
440
def ensure_running (self ):
430
441
# type: () -> None
431
442
443
+ self .soft_shutdown = False
444
+
432
445
pid = os .getpid ()
433
446
434
447
# is running on the right process
@@ -503,6 +516,9 @@ def __init__(self, frequency, options, sdk_info, capture_func):
503
516
504
517
def ensure_running (self ):
505
518
# type: () -> None
519
+
520
+ self .soft_shutdown = False
521
+
506
522
pid = os .getpid ()
507
523
508
524
# is running on the right process
0 commit comments